|
|
@ -45,6 +45,7 @@ import org.springframework.transaction.UnexpectedRollbackException; |
|
|
|
import org.springframework.transaction.support.DefaultTransactionDefinition; |
|
|
|
import org.springframework.transaction.support.DefaultTransactionDefinition; |
|
|
|
import org.springframework.transaction.support.TransactionCallbackWithoutResult; |
|
|
|
import org.springframework.transaction.support.TransactionCallbackWithoutResult; |
|
|
|
import org.springframework.transaction.support.TransactionSynchronization; |
|
|
|
import org.springframework.transaction.support.TransactionSynchronization; |
|
|
|
|
|
|
|
import org.springframework.transaction.support.TransactionSynchronizationAdapter; |
|
|
|
import org.springframework.transaction.support.TransactionSynchronizationManager; |
|
|
|
import org.springframework.transaction.support.TransactionSynchronizationManager; |
|
|
|
import org.springframework.transaction.support.TransactionTemplate; |
|
|
|
import org.springframework.transaction.support.TransactionTemplate; |
|
|
|
|
|
|
|
|
|
|
@ -57,19 +58,19 @@ import static org.mockito.BDDMockito.*; |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
public class DataSourceTransactionManagerTests { |
|
|
|
public class DataSourceTransactionManagerTests { |
|
|
|
|
|
|
|
|
|
|
|
private Connection con; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private DataSource ds; |
|
|
|
private DataSource ds; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private Connection con; |
|
|
|
|
|
|
|
|
|
|
|
private DataSourceTransactionManager tm; |
|
|
|
private DataSourceTransactionManager tm; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Before |
|
|
|
@Before |
|
|
|
public void setUp() throws Exception { |
|
|
|
public void setUp() throws Exception { |
|
|
|
con = mock(Connection.class); |
|
|
|
|
|
|
|
ds = mock(DataSource.class); |
|
|
|
ds = mock(DataSource.class); |
|
|
|
tm = new DataSourceTransactionManager(ds); |
|
|
|
con = mock(Connection.class); |
|
|
|
given(ds.getConnection()).willReturn(con); |
|
|
|
given(ds.getConnection()).willReturn(con); |
|
|
|
|
|
|
|
tm = new DataSourceTransactionManager(ds); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@After |
|
|
|
@After |
|
|
@ -455,13 +456,16 @@ public class DataSourceTransactionManagerTests { |
|
|
|
final TestTransactionSynchronization synch = |
|
|
|
final TestTransactionSynchronization synch = |
|
|
|
new TestTransactionSynchronization(ds, TransactionSynchronization.STATUS_COMMITTED) { |
|
|
|
new TestTransactionSynchronization(ds, TransactionSynchronization.STATUS_COMMITTED) { |
|
|
|
@Override |
|
|
|
@Override |
|
|
|
public void afterCompletion(int status) { |
|
|
|
protected void doAfterCompletion(int status) { |
|
|
|
super.afterCompletion(status); |
|
|
|
super.doAfterCompletion(status); |
|
|
|
tt.execute(new TransactionCallbackWithoutResult() { |
|
|
|
tt.execute(new TransactionCallbackWithoutResult() { |
|
|
|
@Override |
|
|
|
@Override |
|
|
|
protected void doInTransactionWithoutResult(TransactionStatus status) throws RuntimeException { |
|
|
|
protected void doInTransactionWithoutResult(TransactionStatus status) { |
|
|
|
} |
|
|
|
} |
|
|
|
}); |
|
|
|
}); |
|
|
|
|
|
|
|
TransactionSynchronizationManager.registerSynchronization( |
|
|
|
|
|
|
|
new TransactionSynchronizationAdapter() { |
|
|
|
|
|
|
|
}); |
|
|
|
} |
|
|
|
} |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
@ -477,10 +481,50 @@ public class DataSourceTransactionManagerTests { |
|
|
|
assertTrue(synch.beforeCompletionCalled); |
|
|
|
assertTrue(synch.beforeCompletionCalled); |
|
|
|
assertTrue(synch.afterCommitCalled); |
|
|
|
assertTrue(synch.afterCommitCalled); |
|
|
|
assertTrue(synch.afterCompletionCalled); |
|
|
|
assertTrue(synch.afterCompletionCalled); |
|
|
|
|
|
|
|
assertTrue(synch.afterCompletionException instanceof IllegalStateException); |
|
|
|
verify(con, times(2)).commit(); |
|
|
|
verify(con, times(2)).commit(); |
|
|
|
verify(con, times(2)).close(); |
|
|
|
verify(con, times(2)).close(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Test |
|
|
|
|
|
|
|
public void testParticipatingTransactionWithDifferentConnectionObtainedFromSynch() throws Exception { |
|
|
|
|
|
|
|
DataSource ds2 = mock(DataSource.class); |
|
|
|
|
|
|
|
final Connection con2 = mock(Connection.class); |
|
|
|
|
|
|
|
given(ds2.getConnection()).willReturn(con2); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
assertTrue("Hasn't thread connection", !TransactionSynchronizationManager.hasResource(ds)); |
|
|
|
|
|
|
|
assertTrue("Synchronization not active", !TransactionSynchronizationManager.isSynchronizationActive()); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
final TransactionTemplate tt = new TransactionTemplate(tm); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
final TestTransactionSynchronization synch = |
|
|
|
|
|
|
|
new TestTransactionSynchronization(ds, TransactionSynchronization.STATUS_COMMITTED) { |
|
|
|
|
|
|
|
@Override |
|
|
|
|
|
|
|
protected void doAfterCompletion(int status) { |
|
|
|
|
|
|
|
super.doAfterCompletion(status); |
|
|
|
|
|
|
|
Connection con = DataSourceUtils.getConnection(ds2); |
|
|
|
|
|
|
|
DataSourceUtils.releaseConnection(con, ds2); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
tt.execute(new TransactionCallbackWithoutResult() { |
|
|
|
|
|
|
|
@Override |
|
|
|
|
|
|
|
protected void doInTransactionWithoutResult(TransactionStatus status) throws RuntimeException { |
|
|
|
|
|
|
|
TransactionSynchronizationManager.registerSynchronization(synch); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
assertTrue("Hasn't thread connection", !TransactionSynchronizationManager.hasResource(ds)); |
|
|
|
|
|
|
|
assertTrue(synch.beforeCommitCalled); |
|
|
|
|
|
|
|
assertTrue(synch.beforeCompletionCalled); |
|
|
|
|
|
|
|
assertTrue(synch.afterCommitCalled); |
|
|
|
|
|
|
|
assertTrue(synch.afterCompletionCalled); |
|
|
|
|
|
|
|
assertNull(synch.afterCompletionException); |
|
|
|
|
|
|
|
verify(con).commit(); |
|
|
|
|
|
|
|
verify(con).close(); |
|
|
|
|
|
|
|
verify(con2).close(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@Test |
|
|
|
@Test |
|
|
|
public void testParticipatingTransactionWithRollbackOnlyAndInnerSynch() throws Exception { |
|
|
|
public void testParticipatingTransactionWithRollbackOnlyAndInnerSynch() throws Exception { |
|
|
|
tm.setTransactionSynchronization(DataSourceTransactionManager.SYNCHRONIZATION_NEVER); |
|
|
|
tm.setTransactionSynchronization(DataSourceTransactionManager.SYNCHRONIZATION_NEVER); |
|
|
@ -1447,6 +1491,8 @@ public class DataSourceTransactionManagerTests { |
|
|
|
|
|
|
|
|
|
|
|
public boolean afterCompletionCalled; |
|
|
|
public boolean afterCompletionCalled; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public Throwable afterCompletionException; |
|
|
|
|
|
|
|
|
|
|
|
public TestTransactionSynchronization(DataSource dataSource, int status) { |
|
|
|
public TestTransactionSynchronization(DataSource dataSource, int status) { |
|
|
|
this.dataSource = dataSource; |
|
|
|
this.dataSource = dataSource; |
|
|
|
this.status = status; |
|
|
|
this.status = status; |
|
|
@ -1490,6 +1536,15 @@ public class DataSourceTransactionManagerTests { |
|
|
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
@Override |
|
|
|
public void afterCompletion(int status) { |
|
|
|
public void afterCompletion(int status) { |
|
|
|
|
|
|
|
try { |
|
|
|
|
|
|
|
doAfterCompletion(status); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
catch (Throwable ex) { |
|
|
|
|
|
|
|
this.afterCompletionException = ex; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
protected void doAfterCompletion(int status) { |
|
|
|
assertFalse(this.afterCompletionCalled); |
|
|
|
assertFalse(this.afterCompletionCalled); |
|
|
|
this.afterCompletionCalled = true; |
|
|
|
this.afterCompletionCalled = true; |
|
|
|
assertTrue(status == this.status); |
|
|
|
assertTrue(status == this.status); |
|
|
|