Vojtěch Vojtěch - 6 months ago 1169
Java Question

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

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()...



  1. The context of methodB is completely missign in the exception - which is okay I suppose?

  2. Something within the methodB() marked the transaction as rollback only? How can I find it out? Is there for instance a way to check something like
    getCurrentTransaction().isRollbackOnly()?
    - like this I could step through the method and find the cause.


Answer

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.

Comments