Browse Source

Introduce lazyTransactionalConnections flag on TransactionAwareDataSourceProxy

Includes revision of JDBC transaction tests.

Closes gh-29423
pull/30300/head
Juergen Hoeller 2 years ago
parent
commit
47fe61ef79
  1. 21
      spring-jdbc/src/main/java/org/springframework/jdbc/datasource/TransactionAwareDataSourceProxy.java
  2. 228
      spring-jdbc/src/test/java/org/springframework/jdbc/datasource/DataSourceJtaTransactionTests.java
  3. 73
      spring-jdbc/src/test/java/org/springframework/jdbc/datasource/DataSourceTransactionManagerTests.java
  4. 1581
      spring-jdbc/src/test/java/org/springframework/jdbc/support/JdbcTransactionManagerTests.java

21
spring-jdbc/src/main/java/org/springframework/jdbc/datasource/TransactionAwareDataSourceProxy.java

@ -76,6 +76,8 @@ import org.springframework.transaction.support.TransactionSynchronizationManager @@ -76,6 +76,8 @@ import org.springframework.transaction.support.TransactionSynchronizationManager
*/
public class TransactionAwareDataSourceProxy extends DelegatingDataSource {
private boolean lazyTransactionalConnections = true;
private boolean reobtainTransactionalConnections = false;
@ -94,6 +96,18 @@ public class TransactionAwareDataSourceProxy extends DelegatingDataSource { @@ -94,6 +96,18 @@ public class TransactionAwareDataSourceProxy extends DelegatingDataSource {
super(targetDataSource);
}
/**
* Specify whether to obtain the transactional target Connection lazily on
* actual data access.
* <p>The default is "true". Specify "false" to immediately obtain a target
* Connection when a transaction-aware Connection handle is retrieved.
* @since 6.1.2
*/
public void setLazyTransactionalConnections(boolean lazyTransactionalConnections) {
this.lazyTransactionalConnections = lazyTransactionalConnections;
}
/**
* Specify whether to reobtain the target Connection for each operation
* performed within a transaction.
@ -119,7 +133,12 @@ public class TransactionAwareDataSourceProxy extends DelegatingDataSource { @@ -119,7 +133,12 @@ public class TransactionAwareDataSourceProxy extends DelegatingDataSource {
*/
@Override
public Connection getConnection() throws SQLException {
return getTransactionAwareConnectionProxy(obtainTargetDataSource());
DataSource ds = obtainTargetDataSource();
Connection con = getTransactionAwareConnectionProxy(ds);
if (!this.lazyTransactionalConnections && shouldObtainFixedConnection(ds)) {
((ConnectionProxy) con).getTargetConnection();
}
return con;
}
/**

228
spring-jdbc/src/test/java/org/springframework/jdbc/datasource/DataSourceJtaTransactionTests.java

@ -73,6 +73,7 @@ public class DataSourceJtaTransactionTests { @@ -73,6 +73,7 @@ public class DataSourceJtaTransactionTests {
private Transaction transaction = mock();
@BeforeEach
public void setup() throws Exception {
given(dataSource.getConnection()).willReturn(connection);
@ -88,6 +89,7 @@ public class DataSourceJtaTransactionTests { @@ -88,6 +89,7 @@ public class DataSourceJtaTransactionTests {
assertThat(TransactionSynchronizationManager.isActualTransactionActive()).isFalse();
}
@Test
public void testJtaTransactionCommit() throws Exception {
doTestJtaTransaction(false);
@ -110,26 +112,23 @@ public class DataSourceJtaTransactionTests { @@ -110,26 +112,23 @@ public class DataSourceJtaTransactionTests {
JtaTransactionManager ptm = new JtaTransactionManager(userTransaction);
TransactionTemplate tt = new TransactionTemplate(ptm);
boolean condition3 = !TransactionSynchronizationManager.hasResource(dataSource);
assertThat(condition3).as("Hasn't thread connection").isTrue();
boolean condition2 = !TransactionSynchronizationManager.isSynchronizationActive();
assertThat(condition2).as("JTA synchronizations not active").isTrue();
assertThat(!TransactionSynchronizationManager.hasResource(dataSource)).isTrue();
assertThat(!TransactionSynchronizationManager.isSynchronizationActive()).isTrue();
tt.execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(TransactionStatus status) throws RuntimeException {
boolean condition = !TransactionSynchronizationManager.hasResource(dataSource);
assertThat(condition).as("Hasn't thread connection").isTrue();
assertThat(TransactionSynchronizationManager.isSynchronizationActive()).as("JTA synchronizations active").isTrue();
assertThat(status.isNewTransaction()).as("Is new transaction").isTrue();
assertThat(!TransactionSynchronizationManager.hasResource(dataSource)).isTrue();
assertThat(TransactionSynchronizationManager.isSynchronizationActive()).isTrue();
assertThat(status.isNewTransaction()).isTrue();
Connection c = DataSourceUtils.getConnection(dataSource);
assertThat(TransactionSynchronizationManager.hasResource(dataSource)).as("Has thread connection").isTrue();
DataSourceUtils.releaseConnection(c, dataSource);
Connection con = DataSourceUtils.getConnection(dataSource);
assertThat(TransactionSynchronizationManager.hasResource(dataSource)).isTrue();
DataSourceUtils.releaseConnection(con, dataSource);
c = DataSourceUtils.getConnection(dataSource);
assertThat(TransactionSynchronizationManager.hasResource(dataSource)).as("Has thread connection").isTrue();
DataSourceUtils.releaseConnection(c, dataSource);
con = DataSourceUtils.getConnection(dataSource);
assertThat(TransactionSynchronizationManager.hasResource(dataSource)).isTrue();
DataSourceUtils.releaseConnection(con, dataSource);
if (rollback) {
status.setRollbackOnly();
@ -137,10 +136,8 @@ public class DataSourceJtaTransactionTests { @@ -137,10 +136,8 @@ public class DataSourceJtaTransactionTests {
}
});
boolean condition1 = !TransactionSynchronizationManager.hasResource(dataSource);
assertThat(condition1).as("Hasn't thread connection").isTrue();
boolean condition = !TransactionSynchronizationManager.isSynchronizationActive();
assertThat(condition).as("JTA synchronizations not active").isTrue();
assertThat(!TransactionSynchronizationManager.hasResource(dataSource)).isTrue();
assertThat(!TransactionSynchronizationManager.isSynchronizationActive()).isTrue();
verify(userTransaction).begin();
if (rollback) {
verify(userTransaction).rollback();
@ -220,29 +217,26 @@ public class DataSourceJtaTransactionTests { @@ -220,29 +217,26 @@ public class DataSourceJtaTransactionTests {
JtaTransactionManager ptm = new JtaTransactionManager(userTransaction, transactionManager);
final TransactionTemplate tt = new TransactionTemplate(ptm);
tt.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
boolean condition3 = !TransactionSynchronizationManager.hasResource(dsToUse);
assertThat(condition3).as("Hasn't thread connection").isTrue();
boolean condition2 = !TransactionSynchronizationManager.isSynchronizationActive();
assertThat(condition2).as("JTA synchronizations not active").isTrue();
assertThat(!TransactionSynchronizationManager.hasResource(dsToUse)).isTrue();
assertThat(!TransactionSynchronizationManager.isSynchronizationActive()).isTrue();
tt.execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(TransactionStatus status) throws RuntimeException {
boolean condition = !TransactionSynchronizationManager.hasResource(dsToUse);
assertThat(condition).as("Hasn't thread connection").isTrue();
assertThat(TransactionSynchronizationManager.isSynchronizationActive()).as("JTA synchronizations active").isTrue();
assertThat(status.isNewTransaction()).as("Is new transaction").isTrue();
assertThat(!TransactionSynchronizationManager.hasResource(dsToUse)).isTrue();
assertThat(TransactionSynchronizationManager.isSynchronizationActive()).isTrue();
assertThat(status.isNewTransaction()).isTrue();
Connection c = DataSourceUtils.getConnection(dsToUse);
Connection con = DataSourceUtils.getConnection(dsToUse);
try {
assertThat(TransactionSynchronizationManager.hasResource(dsToUse)).as("Has thread connection").isTrue();
c.isReadOnly();
DataSourceUtils.releaseConnection(c, dsToUse);
assertThat(TransactionSynchronizationManager.hasResource(dsToUse)).isTrue();
con.isReadOnly();
DataSourceUtils.releaseConnection(con, dsToUse);
c = DataSourceUtils.getConnection(dsToUse);
assertThat(TransactionSynchronizationManager.hasResource(dsToUse)).as("Has thread connection").isTrue();
con = DataSourceUtils.getConnection(dsToUse);
assertThat(TransactionSynchronizationManager.hasResource(dsToUse)).isTrue();
if (!openOuterConnection) {
DataSourceUtils.releaseConnection(c, dsToUse);
DataSourceUtils.releaseConnection(con, dsToUse);
}
}
catch (SQLException ex) {
@ -253,20 +247,19 @@ public class DataSourceJtaTransactionTests { @@ -253,20 +247,19 @@ public class DataSourceJtaTransactionTests {
tt.execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(TransactionStatus status) throws RuntimeException {
boolean condition = !TransactionSynchronizationManager.hasResource(dsToUse);
assertThat(condition).as("Hasn't thread connection").isTrue();
assertThat(TransactionSynchronizationManager.isSynchronizationActive()).as("JTA synchronizations active").isTrue();
assertThat(status.isNewTransaction()).as("Is new transaction").isTrue();
assertThat(!TransactionSynchronizationManager.hasResource(dsToUse)).isTrue();
assertThat(TransactionSynchronizationManager.isSynchronizationActive()).isTrue();
assertThat(status.isNewTransaction()).isTrue();
try {
Connection c = DataSourceUtils.getConnection(dsToUse);
c.isReadOnly();
assertThat(TransactionSynchronizationManager.hasResource(dsToUse)).as("Has thread connection").isTrue();
DataSourceUtils.releaseConnection(c, dsToUse);
c = DataSourceUtils.getConnection(dsToUse);
assertThat(TransactionSynchronizationManager.hasResource(dsToUse)).as("Has thread connection").isTrue();
DataSourceUtils.releaseConnection(c, dsToUse);
Connection con = DataSourceUtils.getConnection(dsToUse);
con.isReadOnly();
assertThat(TransactionSynchronizationManager.hasResource(dsToUse)).isTrue();
DataSourceUtils.releaseConnection(con, dsToUse);
con = DataSourceUtils.getConnection(dsToUse);
assertThat(TransactionSynchronizationManager.hasResource(dsToUse)).isTrue();
DataSourceUtils.releaseConnection(con, dsToUse);
}
catch (SQLException ex) {
}
@ -282,15 +275,15 @@ public class DataSourceJtaTransactionTests { @@ -282,15 +275,15 @@ public class DataSourceJtaTransactionTests {
if (accessAfterResume) {
try {
if (!openOuterConnection) {
c = DataSourceUtils.getConnection(dsToUse);
con = DataSourceUtils.getConnection(dsToUse);
}
assertThat(TransactionSynchronizationManager.hasResource(dsToUse)).as("Has thread connection").isTrue();
c.isReadOnly();
DataSourceUtils.releaseConnection(c, dsToUse);
assertThat(TransactionSynchronizationManager.hasResource(dsToUse)).isTrue();
con.isReadOnly();
DataSourceUtils.releaseConnection(con, dsToUse);
c = DataSourceUtils.getConnection(dsToUse);
assertThat(TransactionSynchronizationManager.hasResource(dsToUse)).as("Has thread connection").isTrue();
DataSourceUtils.releaseConnection(c, dsToUse);
con = DataSourceUtils.getConnection(dsToUse);
assertThat(TransactionSynchronizationManager.hasResource(dsToUse)).isTrue();
DataSourceUtils.releaseConnection(con, dsToUse);
}
catch (SQLException ex) {
}
@ -298,16 +291,14 @@ public class DataSourceJtaTransactionTests { @@ -298,16 +291,14 @@ public class DataSourceJtaTransactionTests {
else {
if (openOuterConnection) {
DataSourceUtils.releaseConnection(c, dsToUse);
DataSourceUtils.releaseConnection(con, dsToUse);
}
}
}
});
boolean condition1 = !TransactionSynchronizationManager.hasResource(dsToUse);
assertThat(condition1).as("Hasn't thread connection").isTrue();
boolean condition = !TransactionSynchronizationManager.isSynchronizationActive();
assertThat(condition).as("JTA synchronizations not active").isTrue();
assertThat(!TransactionSynchronizationManager.hasResource(dsToUse)).isTrue();
assertThat(!TransactionSynchronizationManager.isSynchronizationActive()).isTrue();
verify(userTransaction, times(6)).begin();
verify(transactionManager, times(5)).resume(transaction);
if (rollback) {
@ -480,31 +471,28 @@ public class DataSourceJtaTransactionTests { @@ -480,31 +471,28 @@ public class DataSourceJtaTransactionTests {
JtaTransactionManager ptm = new JtaTransactionManager(userTransaction, transactionManager);
final TransactionTemplate tt = new TransactionTemplate(ptm);
tt.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
boolean condition3 = !TransactionSynchronizationManager.hasResource(dsToUse);
assertThat(condition3).as("Hasn't thread connection").isTrue();
boolean condition2 = !TransactionSynchronizationManager.isSynchronizationActive();
assertThat(condition2).as("JTA synchronizations not active").isTrue();
assertThat(!TransactionSynchronizationManager.hasResource(dsToUse)).isTrue();
assertThat(!TransactionSynchronizationManager.isSynchronizationActive()).isTrue();
assertThatExceptionOfType(TransactionException.class).isThrownBy(() ->
tt.execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(TransactionStatus status) throws RuntimeException {
boolean condition = !TransactionSynchronizationManager.hasResource(dsToUse);
assertThat(condition).as("Hasn't thread connection").isTrue();
assertThat(TransactionSynchronizationManager.isSynchronizationActive()).as("JTA synchronizations active").isTrue();
assertThat(status.isNewTransaction()).as("Is new transaction").isTrue();
assertThat(!TransactionSynchronizationManager.hasResource(dsToUse)).isTrue();
assertThat(TransactionSynchronizationManager.isSynchronizationActive()).isTrue();
assertThat(status.isNewTransaction()).isTrue();
Connection c = DataSourceUtils.getConnection(dsToUse);
Connection con = DataSourceUtils.getConnection(dsToUse);
try {
assertThat(TransactionSynchronizationManager.hasResource(dsToUse)).as("Has thread connection").isTrue();
c.isReadOnly();
DataSourceUtils.releaseConnection(c, dsToUse);
assertThat(TransactionSynchronizationManager.hasResource(dsToUse)).isTrue();
con.isReadOnly();
DataSourceUtils.releaseConnection(con, dsToUse);
c = DataSourceUtils.getConnection(dsToUse);
assertThat(TransactionSynchronizationManager.hasResource(dsToUse)).as("Has thread connection").isTrue();
con = DataSourceUtils.getConnection(dsToUse);
assertThat(TransactionSynchronizationManager.hasResource(dsToUse)).isTrue();
if (!openOuterConnection) {
DataSourceUtils.releaseConnection(c, dsToUse);
DataSourceUtils.releaseConnection(con, dsToUse);
}
}
catch (SQLException ex) {
@ -514,26 +502,25 @@ public class DataSourceJtaTransactionTests { @@ -514,26 +502,25 @@ public class DataSourceJtaTransactionTests {
tt.execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(TransactionStatus status) throws RuntimeException {
boolean condition = !TransactionSynchronizationManager.hasResource(dsToUse);
assertThat(condition).as("Hasn't thread connection").isTrue();
assertThat(TransactionSynchronizationManager.isSynchronizationActive()).as("JTA synchronizations active").isTrue();
assertThat(status.isNewTransaction()).as("Is new transaction").isTrue();
Connection c = DataSourceUtils.getConnection(dsToUse);
assertThat(TransactionSynchronizationManager.hasResource(dsToUse)).as("Has thread connection").isTrue();
DataSourceUtils.releaseConnection(c, dsToUse);
c = DataSourceUtils.getConnection(dsToUse);
assertThat(TransactionSynchronizationManager.hasResource(dsToUse)).as("Has thread connection").isTrue();
DataSourceUtils.releaseConnection(c, dsToUse);
assertThat(!TransactionSynchronizationManager.hasResource(dsToUse)).isTrue();
assertThat(TransactionSynchronizationManager.isSynchronizationActive()).isTrue();
assertThat(status.isNewTransaction()).isTrue();
Connection con = DataSourceUtils.getConnection(dsToUse);
assertThat(TransactionSynchronizationManager.hasResource(dsToUse)).isTrue();
DataSourceUtils.releaseConnection(con, dsToUse);
con = DataSourceUtils.getConnection(dsToUse);
assertThat(TransactionSynchronizationManager.hasResource(dsToUse)).isTrue();
DataSourceUtils.releaseConnection(con, dsToUse);
}
});
}
finally {
if (openOuterConnection) {
try {
c.isReadOnly();
DataSourceUtils.releaseConnection(c, dsToUse);
con.isReadOnly();
DataSourceUtils.releaseConnection(con, dsToUse);
}
catch (SQLException ex) {
}
@ -542,10 +529,8 @@ public class DataSourceJtaTransactionTests { @@ -542,10 +529,8 @@ public class DataSourceJtaTransactionTests {
}
}));
boolean condition1 = !TransactionSynchronizationManager.hasResource(dsToUse);
assertThat(condition1).as("Hasn't thread connection").isTrue();
boolean condition = !TransactionSynchronizationManager.isSynchronizationActive();
assertThat(condition).as("JTA synchronizations not active").isTrue();
assertThat(!TransactionSynchronizationManager.hasResource(dsToUse)).isTrue();
assertThat(!TransactionSynchronizationManager.isSynchronizationActive()).isTrue();
verify(userTransaction).begin();
if (suspendException) {
@ -586,10 +571,8 @@ public class DataSourceJtaTransactionTests { @@ -586,10 +571,8 @@ public class DataSourceJtaTransactionTests {
}
};
TransactionTemplate tt = new TransactionTemplate(ptm);
boolean condition2 = !TransactionSynchronizationManager.hasResource(dataSource);
assertThat(condition2).as("Hasn't thread connection").isTrue();
boolean condition1 = !TransactionSynchronizationManager.isSynchronizationActive();
assertThat(condition1).as("JTA synchronizations not active").isTrue();
assertThat(!TransactionSynchronizationManager.hasResource(dataSource)).isTrue();
assertThat(!TransactionSynchronizationManager.isSynchronizationActive()).isTrue();
given(userTransaction.getStatus()).willReturn(Status.STATUS_ACTIVE);
for (int i = 0; i < 3; i++) {
@ -598,31 +581,28 @@ public class DataSourceJtaTransactionTests { @@ -598,31 +581,28 @@ public class DataSourceJtaTransactionTests {
tt.execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(TransactionStatus status) throws RuntimeException {
assertThat(TransactionSynchronizationManager.isSynchronizationActive()).as("JTA synchronizations active").isTrue();
boolean condition = !status.isNewTransaction();
assertThat(condition).as("Is existing transaction").isTrue();
assertThat(TransactionSynchronizationManager.isSynchronizationActive()).isTrue();
assertThat(!status.isNewTransaction()).isTrue();
Connection c = DataSourceUtils.getConnection(dataSource);
assertThat(TransactionSynchronizationManager.hasResource(dataSource)).as("Has thread connection").isTrue();
DataSourceUtils.releaseConnection(c, dataSource);
Connection con = DataSourceUtils.getConnection(dataSource);
assertThat(TransactionSynchronizationManager.hasResource(dataSource)).isTrue();
DataSourceUtils.releaseConnection(con, dataSource);
c = DataSourceUtils.getConnection(dataSource);
assertThat(TransactionSynchronizationManager.hasResource(dataSource)).as("Has thread connection").isTrue();
con = DataSourceUtils.getConnection(dataSource);
assertThat(TransactionSynchronizationManager.hasResource(dataSource)).isTrue();
if (releaseCon) {
DataSourceUtils.releaseConnection(c, dataSource);
DataSourceUtils.releaseConnection(con, dataSource);
}
}
});
if (!releaseCon) {
assertThat(TransactionSynchronizationManager.hasResource(dataSource)).as("Still has connection holder").isTrue();
assertThat(TransactionSynchronizationManager.hasResource(dataSource)).isTrue();
}
else {
boolean condition = !TransactionSynchronizationManager.hasResource(dataSource);
assertThat(condition).as("Hasn't thread connection").isTrue();
assertThat(!TransactionSynchronizationManager.hasResource(dataSource)).isTrue();
}
boolean condition = !TransactionSynchronizationManager.isSynchronizationActive();
assertThat(condition).as("JTA synchronizations not active").isTrue();
assertThat(!TransactionSynchronizationManager.isSynchronizationActive()).isTrue();
}
verify(connection, times(3)).close();
}
@ -648,10 +628,10 @@ public class DataSourceJtaTransactionTests { @@ -648,10 +628,10 @@ public class DataSourceJtaTransactionTests {
tt.execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(TransactionStatus status) throws RuntimeException {
Connection c = DataSourceUtils.getConnection(dsToUse);
assertThat(TransactionSynchronizationManager.hasResource(dsToUse)).as("Has thread connection").isTrue();
assertThat(c).isSameAs(connection);
DataSourceUtils.releaseConnection(c, dsToUse);
Connection con = DataSourceUtils.getConnection(dsToUse);
assertThat(TransactionSynchronizationManager.hasResource(dsToUse)).isTrue();
assertThat(con).isSameAs(connection);
DataSourceUtils.releaseConnection(con, dsToUse);
}
});
@ -660,10 +640,10 @@ public class DataSourceJtaTransactionTests { @@ -660,10 +640,10 @@ public class DataSourceJtaTransactionTests {
tt.execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(TransactionStatus status) throws RuntimeException {
Connection c = DataSourceUtils.getConnection(dsToUse);
assertThat(TransactionSynchronizationManager.hasResource(dsToUse)).as("Has thread connection").isTrue();
assertThat(c).isSameAs(connection);
DataSourceUtils.releaseConnection(c, dsToUse);
Connection con = DataSourceUtils.getConnection(dsToUse);
assertThat(TransactionSynchronizationManager.hasResource(dsToUse)).isTrue();
assertThat(con).isSameAs(connection);
DataSourceUtils.releaseConnection(con, dsToUse);
}
});
@ -720,10 +700,10 @@ public class DataSourceJtaTransactionTests { @@ -720,10 +700,10 @@ public class DataSourceJtaTransactionTests {
tt.execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(TransactionStatus status) throws RuntimeException {
Connection c = DataSourceUtils.getConnection(dsToUse);
assertThat(TransactionSynchronizationManager.hasResource(dsToUse)).as("Has thread connection").isTrue();
assertThat(c).isSameAs(connection1);
DataSourceUtils.releaseConnection(c, dsToUse);
Connection con = DataSourceUtils.getConnection(dsToUse);
assertThat(TransactionSynchronizationManager.hasResource(dsToUse)).isTrue();
assertThat(con).isSameAs(connection1);
DataSourceUtils.releaseConnection(con, dsToUse);
}
});
@ -731,10 +711,10 @@ public class DataSourceJtaTransactionTests { @@ -731,10 +711,10 @@ public class DataSourceJtaTransactionTests {
tt.execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(TransactionStatus status) throws RuntimeException {
Connection c = DataSourceUtils.getConnection(dsToUse);
assertThat(TransactionSynchronizationManager.hasResource(dsToUse)).as("Has thread connection").isTrue();
assertThat(c).isSameAs(connection2);
DataSourceUtils.releaseConnection(c, dsToUse);
Connection con = DataSourceUtils.getConnection(dsToUse);
assertThat(TransactionSynchronizationManager.hasResource(dsToUse)).isTrue();
assertThat(con).isSameAs(connection2);
DataSourceUtils.releaseConnection(con, dsToUse);
}
});

73
spring-jdbc/src/test/java/org/springframework/jdbc/datasource/DataSourceTransactionManagerTests.java

@ -67,20 +67,25 @@ import static org.springframework.core.testfixture.TestGroup.LONG_RUNNING; @@ -67,20 +67,25 @@ import static org.springframework.core.testfixture.TestGroup.LONG_RUNNING;
* @since 04.07.2003
* @see org.springframework.jdbc.support.JdbcTransactionManagerTests
*/
public class DataSourceTransactionManagerTests {
public class DataSourceTransactionManagerTests<T extends DataSourceTransactionManager> {
private DataSource ds = mock();
protected DataSource ds = mock();
private Connection con = mock();
protected Connection con = mock();
private DataSourceTransactionManager tm = new DataSourceTransactionManager(ds);
protected DataSourceTransactionManager tm;
@BeforeEach
public void setup() throws Exception {
tm = createTransactionManager(ds);
given(ds.getConnection()).willReturn(con);
}
protected DataSourceTransactionManager createTransactionManager(DataSource ds) {
return new DataSourceTransactionManager(ds);
}
@AfterEach
public void verifyTransactionSynchronizationManagerState() {
assertThat(TransactionSynchronizationManager.getResourceMap()).isEmpty();
@ -123,18 +128,15 @@ public class DataSourceTransactionManagerTests { @@ -123,18 +128,15 @@ public class DataSourceTransactionManagerTests {
private void doTestTransactionCommitRestoringAutoCommit(
boolean autoCommit, boolean lazyConnection, final boolean createStatement) throws Exception {
given(con.getAutoCommit()).willReturn(autoCommit);
if (lazyConnection) {
given(con.getAutoCommit()).willReturn(autoCommit);
given(con.getTransactionIsolation()).willReturn(Connection.TRANSACTION_READ_COMMITTED);
given(con.getWarnings()).willThrow(new SQLException());
}
if (!lazyConnection || createStatement) {
given(con.getAutoCommit()).willReturn(autoCommit);
}
final DataSource dsToUse = (lazyConnection ? new LazyConnectionDataSourceProxy(ds) : ds);
tm = new DataSourceTransactionManager(dsToUse);
tm = createTransactionManager(dsToUse);
TransactionTemplate tt = new TransactionTemplate(tm);
assertThat(TransactionSynchronizationManager.hasResource(dsToUse)).isFalse();
assertThat(TransactionSynchronizationManager.isSynchronizationActive()).isFalse();
@ -213,17 +215,14 @@ public class DataSourceTransactionManagerTests { @@ -213,17 +215,14 @@ public class DataSourceTransactionManagerTests {
private void doTestTransactionRollbackRestoringAutoCommit(
boolean autoCommit, boolean lazyConnection, final boolean createStatement) throws Exception {
given(con.getAutoCommit()).willReturn(autoCommit);
if (lazyConnection) {
given(con.getAutoCommit()).willReturn(autoCommit);
given(con.getTransactionIsolation()).willReturn(Connection.TRANSACTION_READ_COMMITTED);
}
if (!lazyConnection || createStatement) {
given(con.getAutoCommit()).willReturn(autoCommit);
}
final DataSource dsToUse = (lazyConnection ? new LazyConnectionDataSourceProxy(ds) : ds);
tm = new DataSourceTransactionManager(dsToUse);
tm = createTransactionManager(dsToUse);
TransactionTemplate tt = new TransactionTemplate(tm);
assertThat(TransactionSynchronizationManager.hasResource(dsToUse)).isFalse();
assertThat(TransactionSynchronizationManager.isSynchronizationActive()).isFalse();
@ -522,7 +521,7 @@ public class DataSourceTransactionManagerTests { @@ -522,7 +521,7 @@ public class DataSourceTransactionManagerTests {
@Test
public void testParticipatingTransactionWithRollbackOnlyAndInnerSynch() throws Exception {
tm.setTransactionSynchronization(DataSourceTransactionManager.SYNCHRONIZATION_NEVER);
DataSourceTransactionManager tm2 = new DataSourceTransactionManager(ds);
DataSourceTransactionManager tm2 = createTransactionManager(ds);
// tm has no synch enabled (used at outer level), tm2 has synch enabled (inner level)
assertThat(TransactionSynchronizationManager.hasResource(ds)).isFalse();
@ -613,7 +612,7 @@ public class DataSourceTransactionManagerTests { @@ -613,7 +612,7 @@ public class DataSourceTransactionManagerTests {
final TransactionTemplate tt = new TransactionTemplate(tm);
tt.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
PlatformTransactionManager tm2 = new DataSourceTransactionManager(ds2);
PlatformTransactionManager tm2 = createTransactionManager(ds2);
final TransactionTemplate tt2 = new TransactionTemplate(tm2);
tt2.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
@ -662,7 +661,7 @@ public class DataSourceTransactionManagerTests { @@ -662,7 +661,7 @@ public class DataSourceTransactionManagerTests {
final TransactionTemplate tt = new TransactionTemplate(tm);
tt.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
DataSourceTransactionManager tm2 = new DataSourceTransactionManager(ds2);
DataSourceTransactionManager tm2 = createTransactionManager(ds2);
tm2.setTransactionSynchronization(DataSourceTransactionManager.SYNCHRONIZATION_NEVER);
final TransactionTemplate tt2 = new TransactionTemplate(tm2);
tt2.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
@ -1023,6 +1022,42 @@ public class DataSourceTransactionManagerTests { @@ -1023,6 +1022,42 @@ public class DataSourceTransactionManagerTests {
verify(con).close();
}
@Test
public void testTransactionAwareDataSourceProxyWithLazyFalse() throws Exception {
given(con.getAutoCommit()).willReturn(true);
given(con.getWarnings()).willThrow(new SQLException());
TransactionTemplate tt = new TransactionTemplate(tm);
assertThat(TransactionSynchronizationManager.hasResource(ds)).isFalse();
tt.execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(TransactionStatus status) {
// something transactional
assertThat(DataSourceUtils.getConnection(ds)).isEqualTo(con);
TransactionAwareDataSourceProxy dsProxy = new TransactionAwareDataSourceProxy(ds);
dsProxy.setLazyTransactionalConnections(false);
try {
Connection tCon = dsProxy.getConnection();
assertThatExceptionOfType(SQLException.class).isThrownBy(tCon::getWarnings);
tCon.clearWarnings();
assertThat(((ConnectionProxy) dsProxy.getConnection()).getTargetConnection()).isEqualTo(con);
// should be ignored
dsProxy.getConnection().close();
}
catch (SQLException ex) {
throw new UncategorizedSQLException("", "", ex);
}
}
});
assertThat(TransactionSynchronizationManager.hasResource(ds)).isFalse();
InOrder ordered = inOrder(con);
ordered.verify(con).setAutoCommit(false);
ordered.verify(con).commit();
ordered.verify(con).setAutoCommit(true);
verify(con).close();
}
@Test
public void testTransactionAwareDataSourceProxyWithSuspension() throws Exception {
given(con.getAutoCommit()).willReturn(true);

1581
spring-jdbc/src/test/java/org/springframework/jdbc/support/JdbcTransactionManagerTests.java

File diff suppressed because it is too large Load Diff
Loading…
Cancel
Save