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:
- the transactional interceptor intercepts the method call, and starts a transaction, because no transaction is already active
- the method is called
- the method calls MyService.doSth()
- the transactional interceptor intercepts the method call, sees that a transaction is already active, and doesn't do anything
- doSth() is executed and throws an exception
- the transactional interceptor intercepts the exception, marks the transaction as rollbackOnly, and propagates the exception
- ServiceUser.method() catches the exception and returns
- 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:
- the method is called
- the method calls MyService.doSth()
- the transactional interceptor intercepts the method call, sees that no transaction is already active, and thus starts a transaction
- doSth() is executed and throws an exception
- 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
- 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.completeTransactionAfterThrowing(TransactionInfo txInfo, Throwable ex)
and then see what the actual exception is.
Related Topics
How to Send Date in Rest API in Post Method
Is There an Invisible Character That Is Not Regarded as Whitespace
How to Make Program to Continue Running After Exception
403 Forbidden When I Try to Post to My Spring API
How to Update Each Element in a List in Java 8 Using Stream API
How to Know If All the Variables in a Class Are Null
How to Set a Timeout on a Spring Boot Rest API
How to Use Variables in One Method into Another Method
How to Bypass Google Recaptcha for Testing Using Selenium
How to Upload a File and Json Data in Postman
How to Determine If a List of String Contains Null or Empty Elements
How to Make Sonar Ignore Some Classes for Codecoverage Metric
Spring Data JPA - Consider Defining a Bean Named 'Entitymanagerfactory' in Your Configuration
How to Get a List of All the Implementations of an Interface Programmatically in Java
Spring @Requestbody and Enum Value
Convert Multi If-Else to Simple Lambda Expression Code in Java