【问题标题】:TransactionTemplate vs @Transactional(propagation = Propagation.REQUIRES_NEW)TransactionTemplate 与 @Transactional(传播 = Propagation.REQUIRES_NEW)
【发布时间】:2012-04-28 08:06:51
【问题描述】:

有人能解释一下为什么第一个单元测试类有效,而第二个测试类失败并出现锁定等待超时错误吗?

第一个测试类:

public class Test1 extends AbstractTransactionalJUnit4SpringContextTests {

    @Before
    public void setUp() {
       // do stuff through hibernate to populate database with test data
    }

    @Test
    @Transactional(propagation = Propagation.NEVER)
    public void testDeleteObject() {

    TransactionTemplate transactionTemplate = new TransactionTemplate(transactionManager);
    transactionTemplate.execute(new TransactionCallbackWithoutResult() {
        @Override
        protected void doInTransactionWithoutResult(TransactionStatus status) {
            try {
               // execute sql that deletes data populated in setUp() [i.e. this will require locks on the objects].
            }
        });
    }
}

第二次测试类【获取锁等待超时错误】:

public class Test2 extends AbstractTransactionalJUnit4SpringContextTests {

    @Before
    public void setUp() {
       // do stuff through hibernate to populate database with test data
    }

    @Test
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void testObject() {

    // execute sql that deletes data populated in setUp() [i.e. this will require locks on the objects].

    }
}

我知道第二个测试类失败是因为两个事务正在争夺相同的锁,但由于其 in_progress 事务状态,两者都不能放弃锁。我很困惑的是为什么第一个测试类成功执行了 sql。我可能理解错了,但是当 transactionTemplate 执行事务回调时,不会创建新事务吗?在那种情况下,不应该发生同样的事情(锁定等待超时)吗?

【问题讨论】:

    标签: spring hibernate


    【解决方案1】:

    TransactionTemplate 默认情况下不会创建新事务。默认传播行为是 PROPAGATION_REQUIRED。在您的第一种情况下,没有锁定问题,因为设置和删除是在同一个事务中完成的。

    您可以通过将 org.springframework.orm.jpa.JpaTransactionManager 类(甚至整个 org.springframework 包)的日志级别设置为 DEBUG 来查看何时创建新事务或重用现有事务。

    Javadoc for propagation behaviour

    【讨论】:

      【解决方案2】:

      只有当有两个或多个连接访问相同的数据时才会发生死锁。如果测试用例用传播NEVER 注释,您只有一个事务,一个由TransactionTemplate 创建。

      第二种情况对我来说有点模糊。异常意味着有两个并发连接/事务 - 一个用于setUp,一个用于testObject。传播REQUIRES_NEW 确实会强制执行另一个连接,即使检测到一个连接,但我希望setUp 也会在此事务中启动。您可以尝试在testObject 上摆脱@TransactionalAbstractTransactionalJUnit4SpringContextTests 本身带有 @Transactional 注释,默认传播是 REQUIRED 我相信。

      【讨论】:

      • 对,所以在第一种情况下,由于测试类本身也是用@Transactional注解的,所以不会还有两个事务(一个事务通过运行testcase+setup启动,另一个事务启动通过事务模板)?第二种情况似乎也是如此,所以我可能在这里不明白。
      • @Transactional 在一个方法上应该会覆盖 @Transactional 在类上。当从不使用传播时,根本不应该创建任何事务,而不是默认的 REQUIRED 传播。您应该能够通过 org.springframework.transaction 的 DEBUG 级别日志记录来验证这一点。
      猜你喜欢
      • 2019-04-26
      • 2013-03-23
      • 2011-10-05
      • 2012-05-31
      • 2017-11-18
      • 1970-01-01
      • 2020-06-23
      • 2018-05-14
      • 2010-12-09
      相关资源
      最近更新 更多