diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/database/JdbcCursorItemReader.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/database/JdbcCursorItemReader.java index 9d7aa0f79..7d9e2de3d 100644 --- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/database/JdbcCursorItemReader.java +++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/database/JdbcCursorItemReader.java @@ -134,6 +134,8 @@ public class JdbcCursorItemReader extends AbstractItemCountingItemStreamItemR private boolean driverSupportsAbsolute = false; + private boolean participateInExistingTransaction = false; + public JdbcCursorItemReader() { setName(ClassUtils.getShortName(JdbcCursorItemReader.class)); } @@ -171,7 +173,12 @@ public class JdbcCursorItemReader extends AbstractItemCountingItemStreamItemR Assert.state(dataSource != null, "DataSource must not be null."); try { - this.con = DataSourceUtils.getConnection(dataSource); + if (participateInExistingTransaction) { + this.con = DataSourceUtils.getConnection(dataSource); + } + else { + this.con = dataSource.getConnection(); + } preparedStatement = this.con.prepareStatement(sql, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY, ResultSet.HOLD_CURSORS_OVER_COMMIT); applyStatementSettings(preparedStatement); @@ -377,6 +384,19 @@ public class JdbcCursorItemReader extends AbstractItemCountingItemStreamItemR this.driverSupportsAbsolute = driverSupportsAbsolute; } + /** + * Indicate whether the cursor should be opened as part of an existing transaction or if it + * should be opened in its own transaction. The default is for the cursor to be opened in its + * own transaction. If you set this flag to true then you should wrap the DataSource in a + * {@link org.springframework.jdbc.datasource.SingleConnectionDataSource} to prevent the + * connection from being closed after each commit. + * + * @param participateInExistingTransaction false by default + */ + public void setParticipateInExistingTransaction(boolean participateInExistingTransaction) { + this.participateInExistingTransaction = participateInExistingTransaction; + } + /** * Check the result set is in synch with the currentRow attribute. This is * important to ensure that the user hasn't modified the current row. diff --git a/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/database/JdbcCursorItemReaderConfigTests.java b/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/database/JdbcCursorItemReaderConfigTests.java index e7b08b24f..e819bc2d3 100644 --- a/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/database/JdbcCursorItemReaderConfigTests.java +++ b/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/database/JdbcCursorItemReaderConfigTests.java @@ -26,6 +26,14 @@ public class JdbcCursorItemReaderConfigTests { */ @Test public void testUsesCurrentTransaction() throws Exception { + + } + + /* + * Should fail if trying to call getConnection() twice + */ + @Test + public void testUsesItsOwnTransaction() throws Exception { DataSource ds = createMock(DataSource.class); Connection con = createMock(Connection.class); @@ -34,6 +42,7 @@ public class JdbcCursorItemReaderConfigTests { expect(con.prepareStatement("select foo from bar", ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY, ResultSet.HOLD_CURSORS_OVER_COMMIT)).andReturn(ps); expect(ds.getConnection()).andReturn(con); + expect(ds.getConnection()).andReturn(con); con.commit(); replay(con); replay(ds);