Spring @transactional does not start a transaction while testing with JUnit4
I have following configuration.
<beans xmlns="http://www.springframework.org/schema/beans"
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-2.5.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
<bean id="dataSource" class="org.springframework.jdbc.datasource.IsolationLevelDataSourceAdapter">
<property name="targetDataSource">
<bean class="com.microsoft.sqlserver.jdbc.SQLServerConnectionPoolDataSource">
<property name="user" value="user"/>
<property name="password" value="password"/>
<property name="serverName" value="someserver"/>
<property name="databaseName" value="someDBName"/>
<property name="portNumber" value="somePortNumber"/>
</bean>
</property>
</bean>
<!-- this is bean is only used for data extraction module only -->
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.SQLServerDialect</prop>
<prop key="hibernate.format_sql">true</prop>
<prop key="hibernate.show_sql">true</prop>
</props>
</property>
</bean>
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" lazy-init="true">
<property开发者_开发问答 name="persistenceXmlLocation" value="classpath:persistence.xml" />
<property name="dataSource" ref="dataSource"/>
<property name="jpaDialect">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaDialect"/>
</property>
<property name="jpaProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.SQLServerDialect</prop>
<prop key="hibernate.format_sql">false</prop>
<prop key="hibernate.show_sql">false</prop>
<prop key="hibernate.cache.use_second_level_cache">true</prop>
<prop key="hibernate.cache.use_query_cache">true</prop>
</props>
</property>
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>
<!--
Instruct Spring to perform declarative transaction management automatically
on annotated classes. transaction-manager="transactionManager"
-->
<tx:annotation-driven transaction-manager="transactionManager"/>
</beans>
Then, when I ran tests that had an insert statement, they produced error messages as such:
javax.persistence.TransactionRequiredException: Executing an update/delete query
at org.hibernate.ejb.QueryImpl.executeUpdate(QueryImpl.java:47)
After much deliberation, I tried this:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "classpath:services.xml" })
@Transactional(propagation = Propagation.REQUIRED)
@TransactionConfiguration(defaultRollback = true)
@TestExecutionListeners(value = { DependencyInjectionTestExecutionListener.class, TransactionalTestExecutionListener.class})
public class SimpleUnitTest {
@Test
public void simpleTest() throws Exception {
System.out.println(entityManager.getTransaction().isActive());
assertTrue(entityManager.getTransaction().isActive());
}
}
And it failed. entityManager.getTransaction().isActive() was in fact false.
Why wouldn't Transactional test does not begin a transaction?
You need to either add
@TestExecutionListeners(TransactionalTestExecutionListener.class)
or extend from
AbstractTransactionalJUnit4SpringContextTests
to get transactional behavior. (remember, your test class is not a bean, so regular transaction configuration does not apply)
The TransactionalTestExecutionListener
is enabled by default, if you use SpringJUnit4ClassRunner
.
You need to make sure you include the transaction management configuration in your Test context config:
@ContextConfiguration(locations = { "classpath:services.xml" })
So you can check it out by injecting the TM bean:
@Autowired
private PlatformTransactionManager transactionManager;
If the dependency is not resolved, then the transaction config isnot properly located.
During debugging your test, check for the TransactionInterceptor
in your stacktrace.
Because you got two answers related to the configuration, I suppose the problem is not the configuration, but rather the problem how you check whether the transaction is active, and namely how you get that EntityManager
instance.
A possible problem could be: EntityManagerFactory.createEntityManager()
method is used instead of getting an injected EntityManager
.
精彩评论