Hi,
I'm struggling a bit because I cannot get JTA transactions to work in a unit test.
The scenario I'm trying to test is very easy: A DAO inserts a Mail object into a database with JPA. After the insert, the SimpleJdbcTemplate is used to verify that the number of rows in the table has increased.
Everything works fine when a "normal" transaction manager is used. But with JTA, the SimpleJdbcTemplate (inherited because the test class extends AbstractTransactionalJUnit4SpringContextTests) cannot "see" the added row.
How can I solve this problem? Thanks in advance for your help!
Stephan
I use the following libraries:
- Spring 2.5.6
- Bitronix Transaction Manager 1.3.2
- JPA with Hibernate EntityManager 3.4
- PostgreSQL 8.3.7 database
This is the Spring configuration:
Code:
<context:annotation-config />
<tx:annotation-driven />
<bean id="dataSource" class="bitronix.tm.resource.jdbc.PoolingDataSource" init-method="init"
destroy-method="close">
<property name="className" value="org.postgresql.xa.PGXADataSource" />
<property name="uniqueName" value="postgres" />
<property name="maxPoolSize" value="5" />
<property name="testQuery" value="SELECT 1" />
<property name="allowLocalTransactions" value="true" />
<property name="driverProperties">
<props>
<prop key="user">xxx</prop>
<prop key="password">xxx</prop>
<prop key="serverName">xxx</prop>
<prop key="portNumber">5432</prop>
<prop key="databaseName">spring_dev</prop>
</props>
</property>
</bean>
<!-- Bitronix Transaction Manager embedded configuration -->
<bean id="btmConfig" factory-method="getConfiguration" class="bitronix.tm.TransactionManagerServices">
<property name="serverId" value="spring-btm" />
</bean>
<!-- create BTM transaction manager -->
<bean id="BitronixTransactionManager" factory-method="getTransactionManager" class="bitronix.tm.TransactionManagerServices"
depends-on="btmConfig" destroy-method="shutdown" />
<!-- Spring JtaTransactionManager -->
<bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager">
<property name="transactionManager" ref="BitronixTransactionManager" />
<property name="userTransaction" ref="BitronixTransactionManager" />
</bean>
<bean id="jpaVendorAdapter" class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="databasePlatform" value="${jpa.databasePlatform}" />
<property name="database" value="${jpa.database}" />
</bean>
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="jpaVendorAdapter" ref="jpaVendorAdapter" />
<property name="jpaProperties">
<props>
<prop key="hibernate.hbm2ddl.auto">create</prop>
<prop key="hibernate.ejb.naming_strategy">${hibernate.ejb.naming_strategy}</prop>
<prop key="hibernate.transaction.manager_lookup_class">org.hibernate.transaction.BTMTransactionManagerLookup
</prop>
<prop key="hibernate.current_session_context_class">jta</prop>
</props>
</property>
</bean>
<bean id="baseTransactionProxy" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"
abstract="true">
<property name="transactionManager" ref="transactionManager" />
<property name="transactionAttributes">
<props>
<prop key="*">PROPAGATION_REQUIRED, -Exception</prop>
</props>
</property>
</bean>
<bean id="myProxy" parent="baseTransactionProxy">
<property name="target" ref="mailDao" />
</bean>
<bean id="mailDao" class="org.example.mail.dao.impl.MailDaoImpl" />
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<constructor-arg ref="dataSource" />
</bean>
</beans>
And here is the unit test:
Code:
@RunWith(SpringJUnit4ClassRunner.class)
public class JpaTest extends AbstractTransactionalJUnit4SpringContextTests {
protected static final String MAIL_TABLE = "MAIL";
protected MailDao mailDao;
@PersistenceContext
protected EntityManager sharedEntityManager;
@Before
public void init() {
mailDao = (MailDao) applicationContext.getBean("mailDao");
}
@Test
public void addMail_shouldIncrementNumberOfRows() {
int recordsInTableBefore = countRowsInTable(MAIL_TABLE);
mailDao.add(createDefaultMail());
sharedEntityManager.flush();
int rowsInTable = simpleJdbcTemplate.queryForInt("SELECT COUNT(*) FROM " + MAIL_TABLE);
assertThat(rowsInTable, is(recordsInTableBefore + 1));
}
}