事务标记为仅回滚:如何find原因

我在使用@Transactional方法提交事务时遇到问题:

methodA() { methodB() } @Transactional methodB() { ... em.persist(); ... em.flush(); log("OK"); } 

当我从methodA()调用methodB()时,方法成功通过,我可以在日志中看到“OK”。 但是,然后我得到

 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. methodB的上下文在exception中是完全丢失的 – 我想这样可以吗?
  2. methodB()中的某些内容将事务标记为仅回滚? 我怎样才能find它? 有没有例如一种方法来检查像getCurrentTransaction().isRollbackOnly()? – 像这样,我可以通过这个方法来find原因。

当您将方法标记为@Transactional ,方法内出现的任何exception都会将周围的TX标记为仅回滚(即使您捕获它们)。 您可以使用@Transactional注释的其他属性来防止回滚,如:

 @Transactional(rollbackFor=MyException.class, noRollbackFor=MyException2.class) 

我终于明白了这个问题:

 methodA() { methodB() } @Transactional(noRollbackFor = Exception.class) methodB() { ... try { methodC() } catch (...) {...} log("OK"); } @Transactional methodC() { throw new ...(); } 

会发生什么,即使methodB有正确的注释, methodC不会。 当引发exception时,第二个@Transactional只将第一个事务标记为Rollback。

要快速获取导致的exception而不需要重新编码或重build ,请设置一个断点

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

并在堆栈中,通常是一些拦截器。 在那里你可以从某个catch块读取引起的exception。

寻找exception被抛出并被捕获到代码的...部分中。 运行时和回滚应用程序exception在被业务方法抛出时会导致回滚,即使在其他地方被捕获也是如此。

您可以使用上下文来确定事务是否标记为回滚。

 @Resource private SessionContext context; context.getRollbackOnly(); 

我在运行我的应用程序时遇到了这个exception。

最后问题是在SQL查询 。 我的意思是查询是错误的。

请validation您的查询。 这是我的build议

禁用Bean.xml中的transactionmanager

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

注释掉这些行,你会看到导致回滚的exception;)