Spring and Transactions
I’ve been taking a legacy codebase, putting testing in place and refactoring. For DB access I retrofitted the persistence classes to be injected via Spring with a DataSource instead of looking them up via JNDI. IN my Spring context I defined a PlatformTransactionManager.
1 2 3 4 5 6 7 8 9 10 |
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource" scope="singleton" p:driverClassName="${jdbc.driverClassName}" p:url="${jdbc.url}" p:username="${jdbc.username}" p:password="${jdbc.password}" /> <!-- has a property named dataSource which we autowire --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager" autowire="byName" /> |
Then I refer to it in the the test case class.
1 2 3 4 5 |
@TransactionConfiguration(transactionManager = "transactionManager", defaultRollback = true) public class MyTestCases extends AbstractTransactionalJUnit4SpringContextTests { etc. |
Sure enough the console blathered on about starting and rolling back the transaction. The problem is, it wasn’t. It was just saying it did.
How do I know? I checked.
1 2 3 4 5 6 7 8 9 10 11 12 |
int nrowsInMyTable; @BeforeTransaction public void onSetUpInTransaction() throws Exception { nrowsInMyTable = countRowsInTable("SomeTable"); } @AfterTransaction public void verifyFinalDatabaseState() { int rows = countRowsInTable("SomeTable"); assertEquals(nrowsInMyTable, rows); } |
So what was the problem?
I was doing this like every other J(2)EE programmer.
1 |
connection = this.dataSource.getConnection(); |
But with Spring you need to do this instead to associate the transaction thread with the datasource.
1 2 3 4 5 |
connection = DataSourceUtils.getConnection(this.dataSource); and DataSourceUtils.releaseConnection(conn, this.dataSource); |
Then it worked.