public abstract class AbstractCursorItemReader<T> extends AbstractItemCountingItemStreamItemReader<T> implements org.springframework.beans.factory.InitializingBean
Abstract base class for any simple item reader that opens a database cursor and continually retrieves the next row in the ResultSet.
By default the cursor will be opened using a separate connection. The ResultSet for the cursor is held open regardless of commits or roll backs in a surrounding transaction. Clients of this reader are responsible for buffering the items in the case that they need to be re-presented on a rollback. This buffering is handled by the step implementations provided and is only a concern for anyone writing their own step implementations.
There is an option (setUseSharedExtendedConnection(boolean)
that will share the connection
used for the cursor with the rest of the step processing. If you set this flag to true
then you must wrap the DataSource in a ExtendedConnectionDataSourceProxy
to prevent the
connection from being closed and released after each commit performed as part of the step processing.
You must also use a JDBC driver supporting JDBC 3.0 or later since the cursor will be opened with the
additional option of 'HOLD_CURSORS_OVER_COMMIT' enabled.
Each call to AbstractItemCountingItemStreamItemReader.read()
will attempt to map the row at the current position 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. 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 AbstractItemCountingItemStreamItemReader.read()
returns the
ResultSet at the correct row, 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.
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 AbstractItemCountingItemStreamItemReader.read()
again until it has been re-opened.
Known limitation: when used with Derby
setVerifyCursorPosition(boolean)
needs to be false
because ResultSet.getRow()
call used for cursor position verification
is not available for 'TYPE_FORWARD_ONLY' result sets.
Modifier and Type | Field and Description |
---|---|
protected org.apache.commons.logging.Log |
log
Logger available to subclasses
|
protected java.sql.ResultSet |
rs |
static int |
VALUE_NOT_SET |
Constructor and Description |
---|
AbstractCursorItemReader() |
Modifier and Type | Method and Description |
---|---|
void |
afterPropertiesSet()
Assert that mandatory properties are set.
|
protected void |
applyStatementSettings(java.sql.PreparedStatement stmt)
Prepare the given JDBC Statement (or PreparedStatement or
CallableStatement), applying statement settings such as fetch size, max
rows, and query timeout.
|
protected abstract void |
cleanupOnClose() |
protected void |
doClose()
Close the cursor and database connection.
|
protected void |
doOpen()
Execute the statement to open the cursor.
|
protected T |
doRead()
Read next row and map it to item, verify cursor position if
setVerifyCursorPosition(boolean) is true. |
javax.sql.DataSource |
getDataSource()
Public getter for the data source.
|
protected org.springframework.jdbc.support.SQLExceptionTranslator |
getExceptionTranslator()
Creates a default SQLErrorCodeSQLExceptionTranslator for the specified
DataSource if none is set.
|
abstract java.lang.String |
getSql() |
protected void |
handleWarnings(java.sql.Statement statement)
Throw a SQLWarningException if we're not ignoring warnings, else log the
warnings (at debug level).
|
protected void |
initializeConnection() |
boolean |
isUseSharedExtendedConnection() |
protected void |
jumpToItem(int itemIndex)
Use
ResultSet.absolute(int) if possible, otherwise scroll by
calling ResultSet.next() . |
protected abstract void |
openCursor(java.sql.Connection con) |
protected abstract T |
readCursor(java.sql.ResultSet rs,
int currentRow)
Read the cursor and map to the type of object this reader should return.
|
void |
setConnectionAutoCommit(boolean autoCommit)
Set whether "autoCommit" should be overridden for the connection used by the cursor.
|
void |
setDataSource(javax.sql.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 |
setMaxRows(int maxRows)
Sets the limit for the maximum number of rows that any
ResultSet object can contain to the given number. |
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 |
setUseSharedExtendedConnection(boolean useSharedExtendedConnection)
Indicate whether the connection used for the cursor should be used by all other processing
thus sharing the same transaction.
|
void |
setVerifyCursorPosition(boolean verifyCursorPosition)
Allow verification of cursor position after current row is processed by
RowMapper or RowCallbackHandler.
|
close, getCurrentItemCount, isSaveState, open, read, setCurrentItemCount, setMaxItemCount, setSaveState, update
getExecutionContextKey, setExecutionContextName, setName
protected final org.apache.commons.logging.Log log
public static final int VALUE_NOT_SET
protected java.sql.ResultSet rs
public void afterPropertiesSet() throws java.lang.Exception
afterPropertiesSet
in interface org.springframework.beans.factory.InitializingBean
java.lang.IllegalArgumentException
- if either data source or SQL properties
not set.java.lang.Exception
public void setDataSource(javax.sql.DataSource dataSource)
dataSource
- DataSource
to be usedpublic javax.sql.DataSource getDataSource()
protected void applyStatementSettings(java.sql.PreparedStatement stmt) throws java.sql.SQLException
stmt
- PreparedStatement
to be configuredjava.sql.SQLException
- if interactions with provided stmt failsetFetchSize(int)
,
setMaxRows(int)
,
setQueryTimeout(int)
protected org.springframework.jdbc.support.SQLExceptionTranslator getExceptionTranslator()
protected void handleWarnings(java.sql.Statement statement) throws org.springframework.jdbc.SQLWarningException, java.sql.SQLException
statement
- the current statement to obtain the warnings from, if there are any.java.sql.SQLException
- if interaction with provided statement fails.org.springframework.jdbc.SQLWarningException
SQLWarningException
public void setFetchSize(int fetchSize)
ResultSet
object. If the fetch size specified is zero, the
JDBC driver ignores the value.fetchSize
- the number of rows to fetchResultSet.setFetchSize(int)
public void setMaxRows(int maxRows)
ResultSet
object can contain to the given number.maxRows
- the new max rows limit; zero means there is no limitStatement.setMaxRows(int)
public void setQueryTimeout(int queryTimeout)
Statement
object to execute to the given number of seconds.
If the limit is exceeded, an SQLException
is thrown.queryTimeout
- seconds the new query timeout limit in seconds; zero
means there is no limitStatement.setQueryTimeout(int)
public void setIgnoreWarnings(boolean ignoreWarnings)
ignoreWarnings
- if TRUE, warnings are ignoredpublic void setVerifyCursorPosition(boolean verifyCursorPosition)
verifyCursorPosition
- if true, cursor position is verifiedpublic void setDriverSupportsAbsolute(boolean driverSupportsAbsolute)
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.driverSupportsAbsolute
- false
by defaultResultSet.absolute(int)
public void setUseSharedExtendedConnection(boolean useSharedExtendedConnection)
ExtendedConnectionDataSourceProxy
to prevent the
connection from being closed and released after each commit.
When you set this option to true
then the statement used to open the cursor
will be created with both 'READ_ONLY' and 'HOLD_CURSORS_OVER_COMMIT' options. This allows
holding the cursor open over transaction start and commits performed in the step processing.
To use this feature you need a database that supports this and a JDBC driver supporting
JDBC 3.0 or later.useSharedExtendedConnection
- false
by defaultpublic boolean isUseSharedExtendedConnection()
public void setConnectionAutoCommit(boolean autoCommit)
autoCommit
- value used for Connection.setAutoCommit(boolean)
.public abstract java.lang.String getSql()
protected void doClose() throws java.lang.Exception
doClose
in class AbstractItemCountingItemStreamItemReader<T>
java.lang.Exception
- Allows subclasses to throw checked exceptions for interpretation by the frameworkprotected abstract void cleanupOnClose() throws java.lang.Exception
java.lang.Exception
protected void doOpen() throws java.lang.Exception
doOpen
in class AbstractItemCountingItemStreamItemReader<T>
java.lang.Exception
- Allows subclasses to throw checked exceptions for interpretation by the frameworkprotected void initializeConnection()
protected abstract void openCursor(java.sql.Connection con)
protected T doRead() throws java.lang.Exception
setVerifyCursorPosition(boolean)
is true.doRead
in class AbstractItemCountingItemStreamItemReader<T>
null
if the data source is exhaustedjava.lang.Exception
- Allows subclasses to throw checked exceptions for interpretation by the framework@Nullable protected abstract T readCursor(java.sql.ResultSet rs, int currentRow) throws java.sql.SQLException
rs
- The current result setcurrentRow
- Current position of the result setjava.sql.SQLException
- if interactions with the current result set failprotected void jumpToItem(int itemIndex) throws java.lang.Exception
ResultSet.absolute(int)
if possible, otherwise scroll by
calling ResultSet.next()
.jumpToItem
in class AbstractItemCountingItemStreamItemReader<T>
itemIndex
- index of item (0 based) to jump to.java.lang.Exception
- Allows subclasses to throw checked exceptions for interpretation by the framework