简体   繁体   中英

How to force transaction commit in Spring Boot test?

How can I force a transaction commit in Spring Boot (with Spring Data) while running a method and not after the method ?

I've read here that it should be possible with @Transactional(propagation = Propagation.REQUIRES_NEW) in another class but doesn't work for me.

Any hints? I'm using 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"));
    }
}

An approach would be to inject the TransactionTemplate in the test class, remove the @Transactional and @Commit and modify the test method to something like:

...
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...");
    }

Or

new TransactionCallback<Person>() {

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

    // ...
});

instead of the TransactionCallbackWithoutResult callback impl if you plan to add assertions to the person object that was just persisted.

Use the helper class org.springframework.test.context.transaction.TestTransaction (since Spring 4.1).

Tests are rolled back per default. To really commit one needs to do

// 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

And please, don't use @Transactional on Test-Methods! If you have forgotten to start a transaction in your business code, a @Transactional test will never detect it.

Solutions with lambdas.

@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;
    });
}

use as

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

doInTransaction(() -> repo.delete(person));

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM