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.