Transaction Marked as Rollback Only: How to Find the Cause

Transaction marked as rollback only: How do I find the cause

I finally understood the problem:

methodA() {
methodB()
}

@Transactional(noRollbackFor = Exception.class)
methodB() {
...
try {
methodC()
} catch (...) {...}
log("OK");
}

@Transactional
methodC() {
throw new ...();
}

What happens is that even though the methodB has the right annotation, the methodC does not. When the exception is thrown, the second @Transactional marks the first transaction as Rollback only anyway.

How to deal the problem "Transaction was marked for rollback only; cannot commit; "?

I'm guessing your service calls some other component that is annotated with @Transactional, correct? If an exception occurs when calling this other component and is caught in SomeServiceImpl you will be faced with the exception you describe when the transaction system attempts to commit the transaction in methodB. Any exception passing an @Transactional boundary will mark the surrounding transaction as rollback-only, unless you have explicitly told the system otherwise.

If you want the surrounding transaction (i.e. the transaction created for methodB) to "survive" this exception, you'll need to alter the @Transactional annotation on the target component (i.e. the component where the Exception is thrown) with noRollbackFor.

Could not commit JPA transaction: Transaction marked as rollbackOnly

My guess is that ServiceUser.method() is itself transactional. It shouldn't be. Here's the reason why.

Here's what happens when a call is made to your ServiceUser.method() method:

  1. the transactional interceptor intercepts the method call, and starts a transaction, because no transaction is already active
  2. the method is called
  3. the method calls MyService.doSth()
  4. the transactional interceptor intercepts the method call, sees that a transaction is already active, and doesn't do anything
  5. doSth() is executed and throws an exception
  6. the transactional interceptor intercepts the exception, marks the transaction as rollbackOnly, and propagates the exception
  7. ServiceUser.method() catches the exception and returns
  8. the transactional interceptor, since it has started the transaction, tries to commit it. But Hibernate refuses to do it because the transaction is marked as rollbackOnly, so Hibernate throws an exception. The transaction interceptor signals it to the caller by throwing an exception wrapping the hibernate exception.

Now if ServiceUser.method() is not transactional, here's what happens:

  1. the method is called
  2. the method calls MyService.doSth()
  3. the transactional interceptor intercepts the method call, sees that no transaction is already active, and thus starts a transaction
  4. doSth() is executed and throws an exception
  5. the transactional interceptor intercepts the exception. Since it has started the transaction, and since an exception has been thrown, it rollbacks the transaction, and propagates the exception
  6. ServiceUser.method() catches the exception and returns

Can't commit JPA transaction - RollbackException: Transaction marked as rollbackOnly

If you can then, put a debug break-point in org.springframework.transaction.interceptor.TransactionAspectSupport.completeTra‌​nsactionAfterThrowing(TransactionInfo txInfo, Throwable ex) and then see what the actual exception is.



Related Topics



Leave a reply



Submit