如何在集成测试中使用Propagation.REQUIRES_NEW回滚嵌套事务

时间:2011-03-03 09:16:48

标签: hibernate spring transactions integration-testing rollback

我对扩展以下基类的各种服务进行了多次集成测试:

@ContextConfiguration(locations="classpath:applicationContext-test.xml")
@TransactionConfiguration(transactionManager="txManager", defaultRollback=true)
@Transactional
public abstract class IntegrationTestBase extends AbstractTransactionalJUnit4SpringContextTests
{
    //Some setup, filling test data to a HSQLDB-database etc
}

对于大多数情况,这工作正常,但我有一个服务类,其中包含使用propagation=Propagation.REQUIRES_NEW定义的事务。似乎这些事务没有回滚(因为它们是嵌套事务并且显然在“外部”事务中提交?)。回滚“外部”(测试用例级别)事务,至少根据测试日志。提交的事务会破坏一些后来的测试,因为它们已经改变了测试数据。

我可以通过强制测试在测试之间重新创建和重新填充数据库来解决这个问题,但我的问题是,这是预期的行为还是我在测试中做错了什么?是否可以强制嵌套事务从测试代码回滚?

2 个答案:

答案 0 :(得分:12)

这是预期的行为,是使用REQUIRES_NEW的主要原因之一:

  • 能够回滚新事务,但提交外部事务
  • 能够提交新事务,但回滚外部事务

在测试之间重新填充数据库可能是最好的解决方案,我会将此解决方案用于所有测试:这允许测试检查一切是否正常,包括提交(由于刷新,延迟约束可能会失败)等等。)。

但是你真的想要回滚事务,一个解决方案是向你的服务添加一个布尔参数rollbackAtTheEnd,如果这个参数为真,则回滚事务。

答案 1 :(得分:5)

我在Spring improvement ticket上添加了评论。我也会在这里复制它:

我通过转换声明性设置的所有服务方法(如

)来解决这个问题
@Transactional(propagation = REQUIRES_NEW)
public Object doSmth() {
  // doSmthThatRequiresNewTx
}

改为使用TransactionTemplate

private TransactionTemplate transactionTemplate;

public Object doSmth() {
  return transactionTemplate.execute(new TransactionCallback<Object>() {
            @Override
            public Object doInTransaction(TransactionStatus status) {
                // doSmthThatRequiresNewTx
            }
        });
  }

在测试中,我将transactionTemplate的传播行为配置为PROPAGATION_REQUIRED,在真实应用下,我将transactionTemplate的传播行为配置为PROPAGATION_REQUIRES_NEW。它按预期工作。这种解决方法的局限性在于,在测试中,不可能断言内部事务在特殊情况下回滚这一事实。

另一个解决方案是在测试中的doSmth()方法中显式删除数据库中@AfterTransaction所做的所有操作。 “删除”SQL将在新事务中运行,因为其结果将以Spring TransactionConfiguration默认行为的形式进行常规回滚。