I have been using spring transactional management in a project dealing with JUnit Testing. I have gotten this to work fine for my JUnit tests but I cannot get it to work outside of that. Here is my basic scenario:
I have a class which handles DbUnit Initialization similar to this:
@TransactionConfiguration( defaultRollback = true )
@Transactional(propagation=Propagation.REQUIRED)
public class DbUnitManagerImpl implements DbUnitManager {
@Override
public void initializeDatabase(String location) {
// Does work to create a dataset from the file at location
// Calls a function within this class to execute the dbUnit initialization
runSetUp()
}
public void runSetUp() {
// Executes dbUnit call to initialize database
}
}
I am using this class in two different instances. I use it when running JUnit tests to initialize data and I also call these functions from a Backing Bean for a webpage.
The JUnit setup will properly rollback and looks like this:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "classpath:/context/applicationContext-rdCore.xml" })
@TransactionConfiguration( defaultRollback = true )
@Transactional(propagation=Propagation.REQUIRED)
public abstract class BaseDatabaseTest {
@Autowired private DbUnitManager dbUnitManager;
@Test
public void runTest1() {
dbUnitManager.initializeDatabase("D:\\test.xml");
}
}
My backing bean works in a similar way however it allows the DbUnitManagerImpl to do all the transactions. I have debugged that transactions are being started using:
System.out.println(TransactionSynchronizationManager.isActualTransactionActive());
In both cases true is displayed showing that a transaction is being started however rollback only occurs for the JUnit test. The backing bean looks like this:
@Service
@SessionScoped
public class DbUnitInitializerBean {
@Autowired private DbUnitManager manager;
/**
* Initializes the database using the files at <code>location</code>
*/
public void initializeDatabase() {
manager.initializeDatabase("D:\\test.xml);
}
}
A few notes: The three classes mentioned above are obviously stripped down. They also reside in three different java projects. The backing bean resides in a web project which has the following application context:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:cache="http://www.springframework.org/schema/cache"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd
http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd">
<context:annotation-config />
<cache:annotation-driven />
<context:component-scan base-package="com.nph.rd.dbunit" />
<import resource="classpath:/context/applicationContext-rdCore.xml"/>
</beans>
The application context for my test Project which houses the DbUnitManagerImpl class looks like:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:cache="http://www.springframework.org/schema/cache"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd
http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd">
<context:annotation-config />
<cache:annotation-driven />
<import resource="classpath:/context/applicationContext-rdCore.xml"/>
</beans>
The main application context resides in the project which houses my JUnit tests and looks like:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:cache="http://www.springframework.org/schema/cache"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd
http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd">
<context:annotation-config />
<tx:annotation-driven />
<context:component-scan base-package="com.nph.rd.dbunit" />
<context:component-scan base-package="com.nph.dbunit" />
<bean id="dbUnitManager" class="com.nph.dbunit.dao.impl.DbUnitManagerImpl">
</bean>
<!-- allows for ${} replacement in the spring xml configuration from the .properties file on the classpath -->
<context:property-placeholder location="classpath:/properties/core-system.properties" ignore-unresolvable="true"/>
<!-- Transaction Manager -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<!-- OLTP data source -->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource" />
</bean>
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${oltp.database.driverClassName}" />
<property name="url" value="${oltp.database.url}" />
<property name="username" value="${oltp.database.username}" />
<property name="password" value="${oltp.database.password}" />
</bean>
</beans>
The basic end goal is I will have my DbUnitManager class able to rollback on an exception basis when using it from the Backing Bean but have it rollback no matter what when used from my JUnit tests. Currently I have the DbUnitManager class set up to always rollback simply because I am trying to get transaction rollback to work in general. After I get it working I will move it over to rolling back on an exception basis.