org.springframework.batch.item.database
Class JdbcCursorItemReader

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

public class JdbcCursorItemReader
extends ExecutionContextUserSupport
implements ItemReader, InitializingBean, ItemStream

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 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, restartability and skippability. This ensures that each call to read() returns the ResultSet at the correct line, regardless of rollbacks, restarts, or skips.

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. Two values are stored: the current line being processed and the number of lines that have been skipped.

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 input source is notified through the mark() and 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.

Calling skip will indicate that a record is bad and should not be re-presented to the user if the transaction is rolled back. For example, if row 2 is read in, and found to be bad, calling skip will inform the ItemReader. If reading is then continued, and a rollback is necessary because of an error on output, the input source will be returned to row 1. Calling read while on row 1 will move the current row to 3, not 2, because 2 has been marked as skipped.

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 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

Field Summary
protected  ResultSet rs
           
static int VALUE_NOT_SET
           
 
Constructor Summary
JdbcCursorItemReader()
           
 
Method Summary
 void afterPropertiesSet()
          Assert that mandatory properties are set.
 void close(ExecutionContext executionContext)
          Close this input source.
 long getCurrentProcessedRow()
           
protected  SQLExceptionTranslator getExceptionTranslator()
           
 void mark()
          Mark the current row.
 void open(ExecutionContext context)
          Open the stream for the provided ExecutionContext.
 Object read()
          Increment the cursor to the next row, validating the cursor position and passing the resultset to the RowMapper.
 void reset()
          Set the ResultSet's current row to the last marked position.
 void setDataSource(DataSource dataSource)
          Public setter for the data source for injection purposes.
 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 setSaveState(boolean saveState)
          Set whether this ItemReader should save it's state in the ExecutionContext or not
 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.
 void update(ExecutionContext executionContext)
          Indicates that the execution context provided during open is about to be saved.
 
Methods inherited from class org.springframework.batch.item.ExecutionContextUserSupport
getKey, setName
 
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 -

read

public Object read()
            throws Exception
Increment the cursor to the next row, validating the cursor position and passing the resultset to the RowMapper. If read has not been called on this instance before, the cursor will be opened. If there are skipped records for this commit scope, an internal list of skipped records will be checked to ensure that only a valid row is given to the mapper.

Specified by:
read in interface ItemReader
Throws:
DataAccessException
Exception - if an underlying resource is unavailable.

getCurrentProcessedRow

public long getCurrentProcessedRow()

mark

public void mark()
Mark the current row. Calling reset will cause the result set to be set to the current row when mark was called.

Specified by:
mark in interface ItemReader

reset

public void reset()
           throws ResetFailedException
Set the ResultSet's current row to the last marked position.

Specified by:
reset in interface ItemReader
Throws:
DataAccessException
ResetFailedException - if there is a problem with the reset. If a reset fails inside a transaction, it would normally be fatal, and would leave the stream in an inconsistent state. So while this is an unchecked exception, it may be important for a client to catch it explicitly.

close

public void close(ExecutionContext executionContext)
Close this input source. The ResultSet, Statement and Connection created will be closed. This must be called or the connection and cursor will be held open indefinitely!

Specified by:
close in interface ItemStream
Parameters:
executionContext - TODO
See Also:
ItemStream.close(ExecutionContext)

getExceptionTranslator

protected SQLExceptionTranslator getExceptionTranslator()

update

public void update(ExecutionContext executionContext)
Description copied from interface: ItemStream
Indicates that the execution context provided during open is about to be saved. If any state is remaining, but has not been put in the context, it should be added here.

Specified by:
update in interface ItemStream
Parameters:
executionContext - to be updated

open

public void open(ExecutionContext context)
Description copied from interface: ItemStream
Open the stream for the provided ExecutionContext.

Specified by:
open in interface ItemStream

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 -

setSaveState

public void setSaveState(boolean saveState)
Set whether this ItemReader should save it's state in the ExecutionContext or not

Parameters:
saveState -


Copyright © 2008 SpringSource. All Rights Reserved.