【问题标题】:Spring @transactional does not start a transaction while testing with JUnit4使用 JUnit4 进行测试时,Spring @transactional 不会启动事务
【发布时间】:2011-03-22 00:16:08
【问题描述】:

我有以下配置。

<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>

然后,当我运行包含插入语句的测试时,它们会产生如下错误消息:

javax.persistence.TransactionRequiredException: Executing an update/delete query
    at org.hibernate.ejb.QueryImpl.executeUpdate(QueryImpl.java:47)

经过深思熟虑,我尝试了这个:

@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());
   }
}

它失败了。 entityManager.getTransaction().isActive() 实际上是假的。

为什么事务测试不会开始事务?

【问题讨论】:

  • 您的配置似乎正确,但缺少某些内容。启用日志,我在上下文加载阶段看到DEBUG [AnnotationTransactionAttributeSource] Adding transactional method 'XXX' with attribute: PROPAGATION_REQUIRED,ISOLATION_DEFAULT;,然后在运行测试时看到DEBUG [HibernateTransactionManager] Creating new transaction with name [XXX]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT。所以我确定,交易就在那里。
  • 你解决了这个问题吗?
  • 您是否尝试过使用 TransactionTemplate 而不是 @Transactional 注释?
  • 您能告诉我您是如何获得EntityManager 实例的吗?

标签: java hibernate spring jpa transactions


【解决方案1】:

因为你有两个与配置相关的答案,我想问题不在于配置,而在于你如何检查事务是否处于活动状态,即如何获得EntityManager 实例。

可能的问题是:使用EntityManagerFactory.createEntityManager() 方法而不是获取注入的EntityManager

【讨论】:

    【解决方案2】:

    如果您使用SpringJUnit4ClassRunner,则默认启用TransactionalTestExecutionListener

    您需要确保在测试上下文配置中包含事务管理配置:

    @ContextConfiguration(locations = { "classpath:services.xml" })
    

    所以你可以通过注入 TM bean 来检查它:

    @Autowired
    private PlatformTransactionManager transactionManager;
    

    如果依赖关系没有解决,那么事务配置没有正确定位。

    在调试测试期间,检查堆栈跟踪中的 TransactionInterceptor

    【讨论】:

    • 我有你说的一切,但是,我注意到在日志中没有交易开始的痕迹。我曾经在事务启动时看到以下日志:INFO - Began transaction (1): transaction manager 请参阅我的新问题:stackoverflow.com/q/28669280/353985
    【解决方案3】:

    您需要添加

    @TestExecutionListeners(TransactionalTestExecutionListener.class)
    

    或扩展自

    AbstractTransactionalJUnit4SpringContextTests
    

    获得交易行为。 (请记住,您的测试类不是 bean,因此不适用常规事务配置)

    【讨论】:

    • 我尝试使用这两个,但我没有取得太大的成功。我认为 @RunWith(SpringJUnit4ClassRunner.class) 会让测试类被 Spring 识别吗?不?我应该如何配置测试以使用您建议的这两个?
    • 我已经编辑了我的原始问题,以反映我在您提出建议后所做的尝试。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-11-03
    • 2019-01-28
    • 2019-12-06
    • 2020-01-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多