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

JavaSpringHibernateJpaTransactions

Java Problem Overview


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 missing 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.

Java Solutions


Solution 1 - Java

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)

Solution 2 - Java

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.

Solution 3 - Java

To quickly fetch the causing exception without the need to re-code or rebuild, set a breakpoint on

org.hibernate.ejb.TransactionImpl.setRollbackOnly() // Hibernate < 4.3, or
org.hibernate.jpa.internal.TransactionImpl() // as of Hibernate 4.3

and go up in the stack, usually to some Interceptor. There you can read the causing exception from some catch block.

Solution 4 - Java

I struggled with this exception while running my application.

Finally the problem was on the sql query. i mean that the query is wrong.

please verify your query. This is my suggestion

Solution 5 - Java

Found a good explanation with solutions: https://vcfvct.wordpress.com/2016/12/15/spring-nested-transactional-rollback-only/

  1. remove the @Transacional from the nested method if it does not really require transaction control. So even it has exception, it just bubbles up and does not affect transactional stuff.

OR:

  1. if nested method does need transaction control, make it as REQUIRE_NEW for the propagation policy that way even if throws exception and marked as rollback only, the caller will not be affected.

Solution 6 - Java

Look for exceptions being thrown and caught in the ... sections of your code. Runtime and rollbacking application exceptions cause rollback when thrown out of a business method even if caught on some other place.

You can use context to find out whether the transaction is marked for rollback.

@Resource
private SessionContext context;

context.getRollbackOnly();

Solution 7 - Java

There is always a reason why the nested method roll back. If you don't see the reason, you need to change your logger level to debug, where you will see the more details where transaction failed. I changed my logback.xml by adding

<logger name="org.springframework.transaction" level="debug"/>
<logger name="org.springframework.orm.jpa" level="debug"/>

then I got this line in the log:

Participating transaction failed - marking existing transaction as rollback-only

So I just stepped through my code to see where this line is generated and found that there is a catch block which did not throw anything.

private Student add(Student s) {
		try {
			Student retval = studentRepository.save(s);
			return retval;
		} catch (Exception e) {
			
		}
		return null;
	}

Solution 8 - Java

disable the transactionmanager in your Bean.xml

<tx:annotation-driven proxy-target-class="true" transaction-manager="transactionManager"/>
	<bean id="transactionManager"
		class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<property name="dataSource" ref="dataSource"></property>
	</bean>

comment out these lines, and you'll see the exception causing the rollback ;)

Solution 9 - Java

apply the below code in productRepository

@Query("update Product set prodName=:name where prodId=:id ") @Transactional @Modifying int updateMyData(@Param("name")String name, @Param("id") Integer id);

while in junit test apply below code

@Test
public void updateData()
{
  int i=productRepository.updateMyData("Iphone",102);
  
  System.out.println("successfully updated ... ");
  assertTrue(i!=0);
  
}

it is working fine for my code

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionVojtěchView Question on Stackoverflow
Solution 1 - JavaEan VView Answer on Stackoverflow
Solution 2 - JavaVojtěchView Answer on Stackoverflow
Solution 3 - JavaFelixJongleur42View Answer on Stackoverflow
Solution 4 - JavaKumaresan PerumalView Answer on Stackoverflow
Solution 5 - JavaaquajachView Answer on Stackoverflow
Solution 6 - JavaMareenView Answer on Stackoverflow
Solution 7 - JavaJanetView Answer on Stackoverflow
Solution 8 - JavarémyView Answer on Stackoverflow
Solution 9 - JavaAsif RazaView Answer on Stackoverflow