我在@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()...
getCurrentTransaction().isRollbackOnly()?
这样的东西 - 像这样我可以逐步完成方法并查找原因。答案 0 :(得分:85)
当您将方法标记为@Transactional
时,方法中出现的任何异常都会将周围的TX标记为仅回滚(即使您捕获它们)。您可以使用@Transactional
注释的其他属性来阻止它回滚,如:
@Transactional(rollbackFor=MyException.class, noRollbackFor=MyException2.class)
答案 1 :(得分:58)
我终于明白了这个问题:
methodA() {
methodB()
}
@Transactional(noRollbackFor = Exception.class)
methodB() {
...
try {
methodC()
} catch (...) {...}
log("OK");
}
@Transactional
methodC() {
throw new ...();
}
即使methodB
具有正确的注释,但methodC
却没有。抛出异常时,第二个@Transactional
将第一个事务标记为仅回滚。
答案 2 :(得分:36)
要快速获取导致异常而无需重新编码或重建,请在
上设置断点org.hibernate.ejb.TransactionImpl.setRollbackOnly() // Hibernate < 4.3, or
org.hibernate.jpa.internal.TransactionImpl() // as of Hibernate 4.3
然后进入堆栈,通常是一些拦截器。在那里你可以从一些catch块中读取导致的异常。
答案 3 :(得分:9)
我在运行应用程序时遇到了这个异常。
最后 问题出现在SQL查询 上。我的意思是查询是错误的。
请验证您的查询。这是我的建议
答案 4 :(得分:5)
查找代码的...
部分中抛出和捕获的异常。运行时和回滚应用程序异常会在抛出业务方法时导致回滚,即使在其他位置被捕获也是如此。
您可以使用上下文来确定事务是否标记为回滚。
@Resource
private SessionContext context;
context.getRollbackOnly();
答案 5 :(得分:1)
禁用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>
注释掉这些行,你会看到导致回滚的异常;)
答案 6 :(得分:1)
找到了很好的解决方案说明:https://vcfvct.wordpress.com/2016/12/15/spring-nested-transactional-rollback-only/
1)如果确实不需要事务控制,则从嵌套方法中删除@Transacional。因此,即使它有异常,它也会冒泡,并且不会影响事务性事物。
OR:
2)如果嵌套方法确实需要事务控制,则对于传播策略,将其设置为REQUIRE_NEW,这样即使抛出异常并将其标记为仅回滚,调用方也不会受到影响。
答案 7 :(得分:0)
请检查您的 @Transactional 导入应为
[(1.0, 1.8), (2.0, 1.8), (3.0, 0.7)]
[(1.0, 1.8), (2.0, 1.8), (3.0, 0.7)]
[(1.0, 1.8), (2.0, 1.8), (3.0, 0.7)]
答案 8 :(得分:0)
在productRepository中应用以下代码
@Query("update Product set prodName=:name where prodId=:id ")
@Transactional
@Modifying
int updateMyData(@Param("name")String name, @Param("id") Integer id);
在junit测试中,请应用以下代码
@Test
public void updateData()
{
int i=productRepository.updateMyData("Iphone",102);
System.out.println("successfully updated ... ");
assertTrue(i!=0);
}
对于我的代码来说一切正常
答案 9 :(得分:0)
嵌套方法回滚总是有原因的。如果你没有看到原因,你需要改变你的记录器级别来调试,在那里你会看到事务失败的更多细节。我通过添加
更改了我的 logback.xml<logger name="org.springframework.transaction" level="debug"/>
<logger name="org.springframework.orm.jpa" level="debug"/>
然后我在日志中得到了这一行:
Participating transaction failed - marking existing transaction as rollback-only
所以我只是单步调试我的代码,看看这条线是在哪里生成的,发现有一个catch块没有抛出任何东西。
private Student add(Student s) {
try {
Student retval = studentRepository.save(s);
return retval;
} catch (Exception e) {
}
return null;
}