org.springframework.batch.item.database
Class JdbcCursorItemReader

java.lang.Object
  extended by org.springframework.batch.item.support.AbstractBufferedItemReaderItemStream
      extended by org.springframework.batch.item.database.JdbcCursorItemReader
All Implemented Interfaces:
ItemReader, ItemStream, InitializingBean

public class JdbcCursorItemReader
extends AbstractBufferedItemReaderItemStream
implements InitializingBean

Simple item reader that opens a JDBC cursor and continually retrieves the next row in the ResultSet. It is extremely important to note that the JdbcDriver used must be version 3.0 or higher. This is because earlier versions do not support holding a ResultSet open over commits.

Each call to AbstractBufferedItemReaderItemStream.read() will call the provided RowMapper, passing in the ResultSet. There is currently no wrapping of the ResultSet to suppress calls to next(). However, if the RowMapper (mistakenly) increments the current row, the next call to read will verify that the current row is at the expected position and throw a DataAccessException if it is not. This means that, in theory, a RowMapper could read ahead, as long as it returns the row back to the correct position before returning. The reason for such strictness on the ResultSet is due to the need to maintain control for transactions and restartability. This ensures that each call to AbstractBufferedItemReaderItemStream.read() returns the ResultSet at the correct line, regardless of rollbacks or restarts.

ExecutionContext: The current row is returned as restart data, and when restored from that same data, the cursor is opened and the current row set to the value within the restart data. See setDriverSupportsAbsolute(boolean) for improving restart performance.

Transactions: The same ResultSet is held open regardless of commits or roll backs in a surrounding transaction. This means that when such a transaction is committed, the reader is notified through the AbstractBufferedItemReaderItemStream.mark() and AbstractBufferedItemReaderItemStream.reset() so that it can save it's current row number. Later, if the transaction is rolled back, the current row can be moved back to the same row number as it was on when commit was called.

NOTE that the cursor is opened using a separate connection from the rest of the processing in the step. This means that this reader also runs within its own JDBC transaction.

Calling close on this ItemStream will cause all resources it is currently using to be freed. (Connection, ResultSet, etc). It is then illegal to call AbstractBufferedItemReaderItemStream.read() again until it has been opened.

Known limitation: when used with Derby setVerifyCursorPosition(boolean) needs to be false because ResultSet.getRow() call used for cursor position verification throws an exception.

Author:
Lucas Ward, Peter Zozom, Robert Kasanicky

Field Summary
protected  ResultSet rs
           
static int VALUE_NOT_SET
           
 
Constructor Summary
JdbcCursorItemReader()
           
 
Method Summary
 void afterPropertiesSet()
          Assert that mandatory properties are set.
protected  void doClose()
          Close the cursor and database connection.
protected  void doOpen()
          Execute the setSql(String) query.
protected  Object doRead()
          Read next row and map it to item, verify cursor position if setVerifyCursorPosition(boolean) is true.
protected  SQLExceptionTranslator getExceptionTranslator()
          Return the exception translator for this instance.
protected  void jumpToItem(int itemIndex)
          Use ResultSet.absolute(int) if possible, otherwise scroll by calling ResultSet.next().
 void setDataSource(DataSource dataSource)
          Public setter for the data source for injection purposes.
 void setDriverSupportsAbsolute(boolean driverSupportsAbsolute)
          Indicate whether the JDBC driver supports setting the absolute row on a ResultSet.
 void setFetchSize(int fetchSize)
          Gives the JDBC driver a hint as to the number of rows that should be fetched from the database when more rows are needed for this ResultSet object.
 void setIgnoreWarnings(boolean ignoreWarnings)
          Set whether SQLWarnings should be ignored (only logged) or exception should be thrown.
 void setMapper(RowMapper mapper)
          Set the RowMapper to be used for all calls to read().
 void setMaxRows(int maxRows)
          Sets the limit for the maximum number of rows that any ResultSet object can contain to the given number.
 void setPreparedStatementSetter(PreparedStatementSetter preparedStatementSetter)
          Set the PreparedStatementSetter to use if any parameter values that need to be set in the supplied query.
 void setQueryTimeout(int queryTimeout)
          Sets the number of seconds the driver will wait for a Statement object to execute to the given number of seconds.
 void setSql(String sql)
          Set the SQL statement to be used when creating the cursor.
 void setVerifyCursorPosition(boolean verifyCursorPosition)
          Allow verification of cursor position after current row is processed by RowMapper or RowCallbackHandler.
 
Methods inherited from class org.springframework.batch.item.support.AbstractBufferedItemReaderItemStream
close, getCurrentItemCount, mark, open, read, reset, setCurrentItemCount, setName, setSaveState, update
 
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
 

Field Detail

VALUE_NOT_SET

public static final int VALUE_NOT_SET
See Also:
Constant Field Values

rs

protected ResultSet rs
Constructor Detail

JdbcCursorItemReader

public JdbcCursorItemReader()
Method Detail

afterPropertiesSet

public void afterPropertiesSet()
                        throws Exception
Assert that mandatory properties are set.

Specified by:
afterPropertiesSet in interface InitializingBean
Throws:
IllegalArgumentException - if either data source or sql properties not set.
Exception

setDataSource

public void setDataSource(DataSource dataSource)
Public setter for the data source for injection purposes.

Parameters:
dataSource -

getExceptionTranslator

protected SQLExceptionTranslator getExceptionTranslator()
Return the exception translator for this instance. Creates a default SQLErrorCodeSQLExceptionTranslator for the specified DataSource if none is set.


setFetchSize

public void setFetchSize(int fetchSize)
Gives the JDBC driver a hint as to the number of rows that should be fetched from the database when more rows are needed for this ResultSet object. If the fetch size specified is zero, the JDBC driver ignores the value.

Parameters:
fetchSize - the number of rows to fetch
See Also:
ResultSet.setFetchSize(int)

setMaxRows

public void setMaxRows(int maxRows)
Sets the limit for the maximum number of rows that any ResultSet object can contain to the given number.

Parameters:
maxRows - the new max rows limit; zero means there is no limit
See Also:
Statement.setMaxRows(int)

setQueryTimeout

public void setQueryTimeout(int queryTimeout)
Sets the number of seconds the driver will wait for a Statement object to execute to the given number of seconds. If the limit is exceeded, an SQLException is thrown.

Parameters:
queryTimeout - seconds the new query timeout limit in seconds; zero means there is no limit
See Also:
Statement.setQueryTimeout(int)

setIgnoreWarnings

public void setIgnoreWarnings(boolean ignoreWarnings)
Set whether SQLWarnings should be ignored (only logged) or exception should be thrown.

Parameters:
ignoreWarnings - if TRUE, warnings are ignored

setVerifyCursorPosition

public void setVerifyCursorPosition(boolean verifyCursorPosition)
Allow verification of cursor position after current row is processed by RowMapper or RowCallbackHandler. Default value is TRUE.

Parameters:
verifyCursorPosition - if true, cursor position is verified

setMapper

public void setMapper(RowMapper mapper)
Set the RowMapper to be used for all calls to read().

Parameters:
mapper -

setSql

public void setSql(String sql)
Set the SQL statement to be used when creating the cursor. This statement should be a complete and valid SQL statement, as it will be run directly without any modification.

Parameters:
sql -

setPreparedStatementSetter

public void setPreparedStatementSetter(PreparedStatementSetter preparedStatementSetter)
Set the PreparedStatementSetter to use if any parameter values that need to be set in the supplied query.

Parameters:
preparedStatementSetter -

setDriverSupportsAbsolute

public void setDriverSupportsAbsolute(boolean driverSupportsAbsolute)
Indicate whether the JDBC driver supports setting the absolute row on a ResultSet. It is recommended that this is set to true for JDBC drivers that supports ResultSet.absolute() as it may improve performance, especially if a step fails while working with a large data set.

Parameters:
driverSupportsAbsolute - false by default
See Also:
ResultSet.absolute(int)

doClose

protected void doClose()
                throws Exception
Close the cursor and database connection.

Specified by:
doClose in class AbstractBufferedItemReaderItemStream
Throws:
Exception

doOpen

protected void doOpen()
               throws Exception
Execute the setSql(String) query.

Specified by:
doOpen in class AbstractBufferedItemReaderItemStream
Throws:
Exception

doRead

protected Object doRead()
                 throws Exception
Read next row and map it to item, verify cursor position if setVerifyCursorPosition(boolean) is true.

Specified by:
doRead in class AbstractBufferedItemReaderItemStream
Returns:
item
Throws:
Exception

jumpToItem

protected void jumpToItem(int itemIndex)
                   throws Exception
Use ResultSet.absolute(int) if possible, otherwise scroll by calling ResultSet.next().

Overrides:
jumpToItem in class AbstractBufferedItemReaderItemStream
Throws:
Exception


Copyright © 2009 SpringSource. All Rights Reserved.