Package org.springframework.batch.item.database

# Class AbstractCursorItemReader<T>

java.lang.Object
org.springframework.batch.item.ItemStreamSupport
org.springframework.batch.item.support.AbstractItemStreamItemReader<T>
org.springframework.batch.item.support.AbstractItemCountingItemStreamItemReader<T>
org.springframework.batch.item.database.AbstractCursorItemReader<T>

All Implemented Interfaces:
  `ItemReader<T>`, `ItemStream`, `ItemStreamReader<T>`, `org.springframework.beans.factory.InitializingBean`

Direct Known Subclasses:
  `JdbcCursorItemReader`, `StoredProcedureItemReader`

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.

Author:
  Lucas Ward, Peter Zozom, Robert Kasanicky, Thomas Risberg, Michael Minella, Mahmoud Ben Hassine

- ## Field Summary

  Fields
  Modifier and Type
  Field
  Description
  `protected final org.apache.commons.logging.Log`
  `log`
  Logger available to subclasses
  `protected ResultSet`
  `rs`
  `static final int`
  `VALUE_NOT_SET`

- ## Constructor Summary

  Constructors
  Constructor
  Description
  `AbstractCursorItemReader()`

- ## Method Summary

  Modifier and Type
  Method
  Description
  `void`
  `afterPropertiesSet()`
  Assert that mandatory properties are set.
  `protected void`
  `applyStatementSettings(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(Connection connection)`
  Clean up resources.
  `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.
  `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 String`
  `getSql()`
  `protected void`
  `handleWarnings(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(Connection con)`
  `protected abstract T`
  `readCursor(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(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.
  `protected org.springframework.dao.DataAccessException`
  `translateSqlException(String task, String sql, SQLException ex)`

  ### Methods inherited from class org.springframework.batch.item.support.AbstractItemCountingItemStreamItemReader

  `close, getCurrentItemCount, isSaveState, open, read, setCurrentItemCount, setMaxItemCount, setSaveState, update`

  ### Methods inherited from class org.springframework.batch.item.ItemStreamSupport

  `getExecutionContextKey, setExecutionContextName, setName`

  ### Methods inherited from class java.lang.Object

  `clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait`

- ## Field Details

  - ### log

    protected final org.apache.commons.logging.Log log
    Logger available to subclasses

  - ### VALUE_NOT_SET

    public static final int VALUE_NOT_SET
    See Also:
      - Constant Field Values

  - ### rs

    protected ResultSet rs

- ## Constructor Details

  - ### AbstractCursorItemReader

    public AbstractCursorItemReader()

- ## Method Details

  - ### afterPropertiesSet

    public void afterPropertiesSet() throws Exception
    Assert that mandatory properties are set.
    Specified by:
      `afterPropertiesSet` in interface `org.springframework.beans.factory.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` - `DataSource` to be used

  - ### getDataSource

    public DataSource getDataSource()
    Public getter for the data source.
    Returns:
      the dataSource

  - ### applyStatementSettings

    protected void applyStatementSettings(PreparedStatement stmt) throws SQLException
    Prepare the given JDBC Statement (or PreparedStatement or CallableStatement), applying statement settings such as fetch size, max rows, and query timeout. @param stmt the JDBC Statement to prepare
    Parameters:
      `stmt` - `PreparedStatement` to be configured
    Throws:
      `SQLException` - if interactions with provided stmt fail
    See Also:
      - `setFetchSize(int)`
      - `setMaxRows(int)`
      - `setQueryTimeout(int)`

  - ### getExceptionTranslator

    protected org.springframework.jdbc.support.SQLExceptionTranslator getExceptionTranslator()
    Creates a default SQLErrorCodeSQLExceptionTranslator for the specified DataSource if none is set.
    Returns:
      the exception translator for this instance.

  - ### translateSqlException

    protected org.springframework.dao.DataAccessException translateSqlException(String task, String sql, SQLException ex)

  - ### handleWarnings

    protected void handleWarnings(Statement statement) throws org.springframework.jdbc.SQLWarningException, SQLException
    Throw a SQLWarningException if we're not ignoring warnings, else log the warnings (at debug level).
    Parameters:
      `statement` - the current statement to obtain the warnings from, if there are any.
    Throws:
      `SQLException` - if interaction with provided statement fails.
      `org.springframework.jdbc.SQLWarningException`
    See Also:
      - `SQLWarningException`

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

  - ### 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)`

  - ### setUseSharedExtendedConnection

    public void setUseSharedExtendedConnection(boolean useSharedExtendedConnection)
    Indicate whether the connection used for the cursor should be used by all other processing thus sharing the same transaction. If this is set to false, which is the default, then the cursor will be opened using in its connection and will not participate in any transactions started for 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. 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.
    Parameters:
      `useSharedExtendedConnection` - `false` by default

  - ### isUseSharedExtendedConnection

    public boolean isUseSharedExtendedConnection()

  - ### setConnectionAutoCommit

    public void setConnectionAutoCommit(boolean autoCommit)
    Set whether "autoCommit" should be overridden for the connection used by the cursor. If not set, defaults to Connection / Datasource default configuration.
    Parameters:
      `autoCommit` - value used for `Connection.setAutoCommit(boolean)`.
    Since:
      4.0

  - ### getSql

    public abstract String getSql()

  - ### doClose

    protected void doClose() throws Exception
    Close the cursor and database connection. Make call to cleanupOnClose so sub classes can cleanup any resources they have allocated.
    Specified by:
      `doClose` in class `AbstractItemCountingItemStreamItemReader<T>`
    Throws:
      `Exception` - Allows subclasses to throw checked exceptions for interpretation by the framework

  - ### cleanupOnClose

    protected abstract void cleanupOnClose(Connection connection) throws Exception
    Clean up resources.
    Parameters:
      `connection` - to the database
    Throws:
      `Exception` - If unable to clean up resources

  - ### doOpen

    protected void doOpen() throws Exception
    Execute the statement to open the cursor.
    Specified by:
      `doOpen` in class `AbstractItemCountingItemStreamItemReader<T>`
    Throws:
      `Exception` - Allows subclasses to throw checked exceptions for interpretation by the framework

  - ### initializeConnection

    protected void initializeConnection()

  - ### openCursor

    protected abstract void openCursor(Connection con)

  - ### doRead

    @Nullable protected T doRead() throws Exception
    Read next row and map it to item, verify cursor position if `setVerifyCursorPosition(boolean)` is true.
    Specified by:
      `doRead` in class `AbstractItemCountingItemStreamItemReader<T>`
    Returns:
      an item or `null` if the data source is exhausted
    Throws:
      `Exception` - Allows subclasses to throw checked exceptions for interpretation by the framework

  - ### readCursor

    @Nullable protected abstract T readCursor(ResultSet rs, int currentRow) throws SQLException
    Read the cursor and map to the type of object this reader should return. This method must be overridden by subclasses.
    Parameters:
      `rs` - The current result set
      `currentRow` - Current position of the result set
    Returns:
      the mapped object at the cursor position
    Throws:
      `SQLException` - if interactions with the current result set fail

  - ### jumpToItem

    protected void jumpToItem(int itemIndex) throws Exception
    Use `ResultSet.absolute(int)` if possible, otherwise scroll by calling `ResultSet.next()`.
    Overrides:
      `jumpToItem` in class `AbstractItemCountingItemStreamItemReader<T>`
    Parameters:
      `itemIndex` - index of item (0 based) to jump to.
    Throws:
      `Exception` - Allows subclasses to throw checked exceptions for interpretation by the framework