【问题标题】:Manualy execute code in transaction in test with rollback使用回滚在测试中手动执行事务中的代码
【发布时间】:2019-02-24 13:22:48
【问题描述】:

我们使用的是 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 个事务。

【问题讨论】:

  • 请检查 Spring Testing 中的 Programmatic Transaction Management 是否适用于您的情况:docs.spring.io/spring/docs/current/spring-framework-reference/…baeldung.com/spring-test-programmatic-transactions
  • “在一个测试中执行两个事务”与“回滚两个事务”不同-您需要执行后者还是前者?如果是后者,只需通过调用 status.setRollbackOnly(true) 来结束回调 - 或抛出一些运行时异常 - 这将使模板回滚事务......(并将对 execute() 的调用包装在 try/捕获块,以便它们都运行:-))。
  • 嗯 - 但你需要检查你的回调中的断言......

标签: spring spring-boot transactions integration-testing spring-transactions


【解决方案1】:

如果您确实需要启动两个独立运行的事务,对每个事务做一些工作,并且您需要在它们都运行之后检查一些断言,但在提交或回滚之前 - 然后需要提交或在断言之后回滚,您需要设置自己的多线程结构......类似于:

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

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

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

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

【讨论】:

    【解决方案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());
    }
    

    【讨论】:

    • 根据这个参考:books.google.com/… 这个解决方案不应该工作 - 当回调正常返回时,execute() 方法将提交它创建的事务 - 所以没有办法滚动它稍后再交易...
    猜你喜欢
    • 2015-06-19
    • 2012-03-24
    • 1970-01-01
    • 2017-10-25
    • 1970-01-01
    • 1970-01-01
    • 2015-12-31
    • 2022-08-21
    • 1970-01-01
    相关资源
    最近更新 更多