I am having issues with committing a transaction within my @Transactional method:
methodA() { methodB() } @Transactional methodB() { ... em.persist(); ... em.flush(); log("OK"); }
When I call methodB() from methodA(), the method passes successfuly and I can see "OK" in my logs. But then I get
Could not commit JPA transaction; nested exception is javax.persistence.RollbackException: Transaction marked as rollbackOnly org.springframework.transaction.TransactionSystemException: Could not commit JPA transaction; nested exception is javax.persistence.RollbackException: Transaction marked as rollbackOnly at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:521) at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:754) at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:723) at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:393) at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:120) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172) at org.springframework.aop.framework.Cglib2AopProxy$DynamicAdvisedInterceptor.intercept(Cglib2AopProxy.java:622) at methodA()...
getCurrentTransaction().isRollbackOnly()?
- like this I could step through the method and find the cause.As a result of an error condition or exception, an application can determine that the current transaction should be rolled back. However, the application should not attempt to rollback the transaction directly.
javax.transaction RollbackException exception is thrown when the transaction has been marked for rollback only or the transaction has been rolled back instead of committed. This is a local exception thrown by methods in the UserTransaction , Transaction , and TransactionManager interfaces.
To rollback a transaction you can use @Transaction annotation. You can either implement it on method level or class level. Class level @Transactional(rollbackFor = Exception.
When you mark your method as @Transactional
, occurrence of any exception inside your method will mark the surrounding TX as roll-back only (even if you catch them). You can use other attributes of @Transactional
annotation to prevent it of rolling back like:
@Transactional(rollbackFor=MyException.class, noRollbackFor=MyException2.class)
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With