使用回滚手动执行测试中的事务中的代码

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用回滚手动执行测试中的事务中的代码相关的知识,希望对你有一定的参考价值。

我们正在使用spring boot 2,在我们的集成测试中,我们需要在事务中手动执行一些代码,在事务结束时和断言之后,我们希望回滚该事务。

我们使用显式定义的事务而不是@Transactional,因为有时我们需要在测试2事务中执行。

这是测试样本:

@Test
public void fooTest() {

    // transaction 1
    transactionTemplate.execute(new TransactionCallbackWithoutResult() {
        @Override
            protected void doInTransactionWithoutResult(TransactionStatus status) {
                // some code in transaction
            }

    // transaction 2
    transactionTemplate.execute(new TransactionCallbackWithoutResult() {
        @Override
            protected void doInTransactionWithoutResult(TransactionStatus status) {
                // some code in transaction
            }

    // here I need rollback these transactions for clean db for another tests
}

你能告诉我如何在我们的案例中使用回滚来回滚两个事务吗?这是我们维护的旧代码,所以如果可以在启动2中做得更好,我会感激任何建议。我们只需要在一次测试中执行2个事务。

答案

TransactionStatus中存储对每个AtomicReference的引用,并在测试后使用事务管理器回滚它们。

@Test
void test() {
  final AtomicReference<TransactionStatus> first = new AtomicReference<>();
  final AtomicReference<TransactionStatus> second = new AtomicReference<>();
  transactionTemplate.execute(new TransactionCallbackWithoutResult() {
    @Override
    protected void doInTransactionWithoutResult(TransactionStatus status) {
      // some code in transaction
      first.set(status);
    }
  });

  // transaction 2
  transactionTemplate.execute(new TransactionCallbackWithoutResult() {
    @Override
    protected void doInTransactionWithoutResult(TransactionStatus status) {
      // some code in transaction
      second.set(status);
    }
  });
  transactionTemplate.getTransactionManager().rollback(first.get());
  transactionTemplate.getTransactionManager().rollback(second.get());
}
另一答案

如果你真的需要启动两个独立运行的事务,在每个事务上做一些工作,你需要在它们都运行之后检查一些断言,但是在提交或回滚之前 - 然后需要提交或回滚两个断言,你需要建立自己的多线程结构...像:

execute(AssertCallback aC, TransactionCallback ... tCs);

该方法将为每个tC启动一个线程。每个线程都会在每个线程中调用回调方法,并在屏障上的返回块上调用,直到执行tCs的所有线程都到达同一个点。主线程也将等待所有tC线程阻塞,然后它将运行aC回调,当它返回时,释放所有tC线程,以便它们可以提交/回滚并退出。

这看起来有点奇怪,因为aC回调无法“看到”任何tC回调所做的任何工作,因为那是在尚未提交的事务中。

我从未见过这个实现......但是,如果你想看看我在说什么,请看看这里的并行测试项目:https://github.com/moilejter/examples.git

以上是关于使用回滚手动执行测试中的事务中的代码的主要内容,如果未能解决你的问题,请参考以下文章

使用栈处理回滚

AOP实现LCN手动回滚事务

如何手动控制java中的事务

外部事务失败时回滚内部事务

知识点:事务手动回滚方式

Mysql——undo日志事务id