1
@Service
public class TransactionClass{

    @AutoWire
    TransactionClass tranClass;

    @Autowire
    TransactionRepository transRepo;

    public void methodA(Data data){
        try{
             methodB(data)
        }catch(Exception e){
            //some logic
        }
   }

   public void methodB(Data data){
       //some logic
       tranClass.methodC(data)
   }

  @Transactional
  public void methodC(Data data){
      //some logic
      transRepo.save(data);
      throw new RuntimeException();
  }
}

The problem is that the methodC() isn't getting rolled back even though an unchecked exception is thrown.

Aman
  • 1,627
  • 13
  • 19
Koushik
  • 21
  • 4
  • Because `methodC()` doesn't have an on-going transaction as explained in the dupe. The only transaction will happen in `transRepo.save(data);`. – Kayaman Nov 10 '20 at 09:11
  • But I just want rollback to happen in methodC. But even as the Runtime Exception is thrown after transRepo.save(data); still data gets saved in the DB. – Koushik Nov 10 '20 at 09:30
  • Oh I didn't notice you're doing a self-injection for `TransactionClass`. That is how it should generally work, so the mistake is probably somewhere in your actual code. – Kayaman Nov 10 '20 at 09:58
  • How do you call methodC ? – Mick Nov 10 '20 at 10:06
  • @Mick `methodC()` is called using the reference of `TransactionClass` . – Koushik Nov 10 '20 at 10:24
  • You mean a reference to a spring proxy implementing TransactionClass by using an autowired instance, right? It is crucial for transactions to work. – Mick Nov 10 '20 at 10:26
  • @Mike yes correct. so spring will create a proxy by extending `TransactionClass`. So that proxy should start transaction in `methodC` and after the RuntimeException, it should auto roll back. But that is not happening. – Koushik Nov 10 '20 at 10:29
  • @Koushik You can try to remove `tranClass` field. And path `tranClass` as a parameter `void methodB(Data data, TransactionClass tranClass)`. Has anything changed? – v.ladynev Nov 10 '20 at 11:02
  • For me everything works as expected: if I throw RuntimeException in methodC it does role back if I throw e.g. an IOException in methodC it does not. You are also calling methodA to start? –  Nov 10 '20 at 11:34
  • @sebastian Yes...so methodA will call methodB and then methodB will call methodC with the reference of the same class....due to spring's proxy rule.....but for me in the logs it's shows that rollback is initinated but when I check Db, then the data is already saved. – Koushik Nov 10 '20 at 11:49
  • I replicated the code and wrote a test method, which clearly shows there was a role back. Have you tried this in a test or with a request to a controller? –  Nov 10 '20 at 13:44
  • Yes roll Back is initiated but the problem is this... – Koushik Nov 10 '20 at 14:14
  • doCleanupAfterCompletion - Not closing pre-bound JPA EntityManager after transaction – Koushik Nov 10 '20 at 14:14

2 Answers2

1

To check how transactions work using logs, just add this to the application.yaml

logging.level.org.springframework.transaction.interceptor: TRACE
logging.level.org.springframework.orm.jpa.JpaTransactionManager: DEBUG

logging.level.org.hibernate.SQL: DEBUG
spring.jpa.properties.hibernate.use_sql_comments: true
v.ladynev
  • 19,275
  • 8
  • 46
  • 67
1

Transactional Method not rolling back as it had multi DB connection. So @Transactional will roll back for the only primary configuration and we can have only one primary configuration as well in an application. The solution to this is to use a chained transaction.

Refer to this link for furthermore on the chained transaction: https://blog.usejournal.com/springboot-jpa-rollback-transaction-with-multi-databases-53e6f2f143d6

Koushik
  • 21
  • 4