How to force transaction commit in Spring Boot test?

Viewed 12397

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

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

Solutions with lambdas.

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

use as

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

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