Jpa transaction javax.persistence.RollbackException: Transaction marked as rollbackOnly

java, jpa, spring

Solution

The JPA specification mandates that the transaction is marked for rollback when an OptimisticLockException occurs. And I don't know which JPA engine you use, but at least for Hibernate (and I would expect the same thing for other engines), the documentation says:

If the Session throws an exception, including any SQLException, immediately rollback the database transaction, call Session.close() and discard the Session instance. Certain methods of Session will not leave the session in a consistent state. No exception thrown by Hibernate can be treated as recoverable. Ensure that the Session will be closed by calling close() in a finally block.

So if you get such an exception, your best bet is to let the transaction rollback, and retry.

Problem

I've got an application that's doing a bunch of writes to various database tables via jpa. One of those writes can cause an optimistic lock exception. If one is thrown, it's not a big deal and I want the rest of the transaction to commit. I took a look at the no-rollback functionality on the spring transaction via: ``` <bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate"> <constructor-arg ref="transactionManager"/> <constructor-arg ref="ignoreOptimisticLockingExceptionRule"/> </bean> <bean id="ignoreOptimisticLockingExceptionRule" class="org.springframework.transaction.interceptor.RuleBasedTransactionAttribute"> <property name="rollbackRules"> <list> <bean class="org.springframework.transaction.interceptor.NoRollbackRuleAttribute"> <constructor-arg value="javax.persistence.OptimisticLockException"/> </bean> </list> </property> </bean> <bean class="org.springframework.orm.jpa.JpaTransactionManager" id="transactionManager"> <property name="entityManagerFactory" ref="entityManagerFactory" /> </bean> ``` My app catches the OLException around the merge method of the entity that will throw this exception, but the transaction still gets rolled back. I did some digging around to see what was up, and in the doCommit method of JpaTransactionManager is where javax.persistence.RollbackException: Transaction marked as rollbackOnly gets thrown. It gets thrown because the rollbackOnly flag (in TransactionImpl) was marked as true. Digging deeper into that, i see that merge method in AbstractEntityMangerImpl ultimately marks the transaction as rollbackonly which then triggers the exception further up. I don't see where the RuleBasedTransactionAttributes get applied though. I don't know if i have that setup properly. Thanks!

Original source