Search code examples
springspring-data-jpatransactionsspring-dataspring-transactions

Spring @Transactional does not work when I call a method inside of it. How can I slove it?


I have an entity with 3 field (id, name and age). I have created a repository (PersonRepository) in which I want to see how Transaction works. I find strange that if I insert a method call inside a method, this does not work as expected.

public void nestedTransaction() {
        personRepository.save(new Person(11L, "A1", 26));
        childTransaction();
}

@Transactional(propagation = Propagation.REQUIRED)
public void childTransaction() {
    personRepository.save(new Person(10L, "A2", 26));
    throw new RuntimeException("ExceptionTest child");
}

After the autowiring of PersonRepository that contain the above methods, I call:

try {
    serviceTransaction.nestedTransaction();
} catch (Exception e) {
    System.out.println("Exception: "+e.getMessage());
}

Please do not pay attention on the fact that I'm using System.out.println instead of logging, this is just a test for understanding @Transactional. However, I expect that in my DB there is the entity (11L, "A1", 26) but not the entity (10L, "A2", 26)) instead I have both. Why this happen?

I already know that I can use transactionTemplate and it works using it. For example:

public void nestedTransaction() {
    transactionTemplate.setTimeout(1000);
    transactionTemplate.setIsolationLevel(TransactionDefinition.ISOLATION_REPEATABLE_READ);
    transactionTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
    personRepository.save(new Person(11L, "Ale2", 26));
    transactionTemplate.execute(new TransactionCallbackWithoutResult() {
            
       @Override
       protected void doInTransactionWithoutResult(TransactionStatus status) {
            childTransaction();
       }
    });
}

Can anyone explain this behaviour and how to solve it?


Solution

  • You need to put the @Transactional annotation above the nestedTransaction() method as well for the transaction to commit. Also, the propagation = Propagation.REQUIRED property is default, so you don't need to specify it.