In a nutshell
My command line Java application copies data from one datasource to another without using XA. I have configured two separate datasources and would like a JUnit test that can rollback data on both datasources. I use DBUnit to load data into the "source" database, but I cannot get this to rollback. I can get the "target" datasource to rollback.
My Code
Given this config...
<tx:annotation-driven />
<!-- note the default transactionManager name on this one -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSourceA" />
</bean>
<bean id="transactionManagerTarget" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSourceB" />
</bean>
and this code...
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations={"classpath:resources/spring-context.xml",
"classpath:resources/spring-db.xml"})
@Transactional
@TransactionConfiguration(transactionManager = "transactionManagerTarget", defaultRollback = true)
public class MyIntegrationTest {
@Autowired
private MyService service;
@Autowired
@Qualifier("dataSourceA")
private DataSource dataSourceA;
private IDataSet loadedDataSet;
/**
* Required by DbUnit
*/
@Before
public void setUp() throws Exception {
SybaseInsertIdentityOperation.TRUNCATE_TABLE.execute(getConnection(), getDataSet());
SybaseInsertIdentityOperation.INSERT.execute(getConnection(), getDataSet());
}
/**
* Required by DbUnit
*/
protected IDataSet getDataSet() throws Exception {
loadedDataSet = DbUnitHelper.getDataSetFromFile(getConnection(), "TestData.xml");
return loadedDataSet;
}
/**
* Required by DbUnit
*/
protected IDatabaseConnection getConnection() throws Exception{
return new DatabaseConnection(dataSourceA.getConnection());
}
@Test
public void testSomething() {
// service.doCopyStuff();
}
}
The problem as I see it, is that @TransactionConfiguration
only states the target datasource for enabling a rollback. DBUnit is being passed dataSourceA
explicitly and is picking up the default transaction manager named transactionManager
(I'm not sure how) which has not been told to rollback.
Question
How can I tell both transaction managers to rollback?
Can I use a single transaction manager when my datasources do not support XA transactions?
Note: The application does not require a transaction manager on dataSourceA when running in production as it will only be read-only. This issue is for my tests classes only.
Use the <qualifier>
element inside your transaction manager definition.
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSourceA" />
<qualifier value="transactionManager" />
</bean>
<bean id="transactionManagerTarget" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSourceB" />
<qualifier value="transactionManagerTarget" />
</bean>
Then you can reference which one you want to use directly in the @Transactional
annotation, i.e.
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations={"classpath:resources/spring-context.xml",
"classpath:resources/spring-db.xml"})
@Transactional("transactionManagerTarget")
@TransactionConfiguration(defaultRollback = true)
public class MyIntegrationTest {
...