【问题标题】:How to force transaction commit in Spring Boot test?如何在 Spring Boot 测试中强制事务提交?
【发布时间】:2017-10-20 03:49:12
【问题描述】:

如何在 Spring Boot(使用 Spring Data)在运行方法时强制提交事务并且在方法之后不?

我在这里读到过,@Transactional(propagation = Propagation.REQUIRES_NEW) 应该可以在另一个课程中使用,但对我不起作用。

有什么提示吗?我正在使用 Spring Boot v1.5.2.RELEASE。

@RunWith(SpringRunner.class)
@SpringBootTest
public class CommitTest {

    @Autowired
    TestRepo repo;

    @Transactional
    @Commit
    @Test
    public void testCommit() {
        repo.createPerson();
        System.out.println("I want a commit here!");
        // ...
        System.out.println("Something after the commit...");
    }
}

@Repository
public class TestRepo {

    @Autowired
    private PersonRepository personRepo;

    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void createPerson() {
        personRepo.save(new Person("test"));
    }
}

【问题讨论】:

  • 不让您的测试事务化,那么您的软件就会像在您的环境中那样运行。如果您的事务完全不起作用,那么您的配置可能有问题。

标签: java spring-boot transactions spring-data spring-data-jpa


【解决方案1】:

使用辅助类 org.springframework.test.context.transaction.TestTransaction(自 Spring 4.1 起)。

默认情况下会回滚测试。真正的承诺需要做的事情

// do something before the commit 

TestTransaction.flagForCommit(); // need this, otherwise the next line does a rollback
TestTransaction.end();
TestTransaction.start();

// do something in new transaction

【讨论】:

  • 虽然这在非引导环境中有效,但在 Spring Boot 中我很难完成这项工作,因为需要以某种方式启用 TransactionalTestExecutionListener,而那个与 Spring Boot 注释配合得不好。跨度>
  • 奇怪。我在 SpringBootTests 中将它与 @SpringBootTest 和 @Transactional 结合使用
【解决方案2】:

一种方法是在测试类中注入TransactionTemplate,删除@Transactional 和@Commit,并将测试方法修改为:

...
public class CommitTest {

    @Autowired
    TestRepo repo;

    @Autowired
    TransactionTemplate txTemplate;

    @Test
    public void testCommit() {
        txTemplate.execute(new TransactionCallbackWithoutResult() {

          @Override
          protected void doInTransactionWithoutResult(TransactionStatus status) {
            repo.createPerson();
            // ...
          }
        });

        // ...
        System.out.println("Something after the commit...");
    }

或者

new TransactionCallback<Person>() {

    @Override
    public Person doInTransaction(TransactionStatus status) {
      // ...
      return person
    }

    // ...
});

如果您打算将断言添加到刚刚持久化的 person 对象,则不要使用 TransactionCallbackWithoutResult 回调 impl。

【讨论】:

    【解决方案3】:

    使用 lambda 的解决方案。

    import java.lang.Runnable;
    import java.util.function.Supplier;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.transaction.support.TransactionTemplate;
    
    @Autowired
    TestRepo repo;
    
    @Autowired
    TransactionTemplate txTemplate;
    
    private <T> T doInTransaction(Supplier<T> operation) {
        return txTemplate.execute(status -> operation.get());
    }
    
    private void doInTransaction(Runnable operation) {
        txTemplate.execute(status -> {
            operation.run();
            return null;
        });
    }
    

    用作

    Person saved = doInTransaction(() -> repo.save(buildPerson(...)));
    
    doInTransaction(() -> repo.delete(person));
    

    【讨论】:

    • 请在顶部添加您的导入,以便清楚您使用哪些类。您也可以删除代码中未使用的 TestRpeo。
    猜你喜欢
    • 2019-04-03
    • 2014-11-14
    • 1970-01-01
    • 2019-11-25
    • 1970-01-01
    • 2016-06-21
    • 2019-06-08
    • 2021-10-09
    • 2023-03-04
    相关资源
    最近更新 更多