Voj*_*ěch 83 java spring hibernate jpa transactions
我在@Transactional方法中提交事务时遇到问题:
methodA() {
methodB()
}
@Transactional
methodB() {
...
em.persist();
...
em.flush();
log("OK");
}
Run Code Online (Sandbox Code Playgroud)
当我从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()...
Run Code Online (Sandbox Code Playgroud)
getCurrentTransaction().isRollbackOnly()?- 像这样我可以逐步完成方法并找到原因.Ean*_*n V 92
当您将方法标记为时,方法中@Transactional出现的任何异常都会将周围的TX标记为仅回滚(即使您捕获它们).您可以使用@Transactional注释的其他属性来阻止它回滚,如:
@Transactional(rollbackFor=MyException.class, noRollbackFor=MyException2.class)
Run Code Online (Sandbox Code Playgroud)
Voj*_*ěch 62
我终于明白了这个问题:
methodA() {
methodB()
}
@Transactional(noRollbackFor = Exception.class)
methodB() {
...
try {
methodC()
} catch (...) {...}
log("OK");
}
@Transactional
methodC() {
throw new ...();
}
Run Code Online (Sandbox Code Playgroud)
会发生什么是即使methodB有正确的注释,methodC也没有.抛出异常时,第二个@Transactional事务将第一个事务标记为仅回滚.
Fel*_*r42 40
要快速获取导致的异常而无需重新编码或重建,请设置断点
org.hibernate.ejb.TransactionImpl.setRollbackOnly() // Hibernate < 4.3, or
org.hibernate.jpa.internal.TransactionImpl() // as of Hibernate 4.3
Run Code Online (Sandbox Code Playgroud)
然后进入堆栈,通常是一些拦截器.在那里你可以从一些catch块中读取导致异常.
找到了一个很好的解决方案解释:https : //vcfvct.wordpress.com/2016/12/15/spring-nested-transactional-rollback-only/
1) 如果它并不真正需要事务控制,则从嵌套方法中删除 @Transacional。所以即使它有异常,它也只是冒泡,不会影响事务性的东西。
或者:
2)如果嵌套方法确实需要事务控制,则将其设置为传播策略的REQUIRE_NEW,这样即使抛出异常并标记为仅回滚,调用者也不会受到影响。
嵌套方法回滚总是有原因的。如果您没有看到原因,则需要将记录器级别更改为调试,您将在其中看到事务失败的更多详细信息。我通过添加更改了 logback.xml
<logger name="org.springframework.transaction" level="debug"/>
<logger name="org.springframework.orm.jpa" level="debug"/>
Run Code Online (Sandbox Code Playgroud)
然后我在日志中得到这一行:
Participating transaction failed - marking existing transaction as rollback-only
Run Code Online (Sandbox Code Playgroud)
所以我只是单步执行我的代码来查看这一行是在哪里生成的,发现有一个 catch 块没有抛出任何东西。
private Student add(Student s) {
try {
Student retval = studentRepository.save(s);
return retval;
} catch (Exception e) {
}
return null;
}
Run Code Online (Sandbox Code Playgroud)
查找抛出异常并在...代码的各个部分中捕获的异常.运行时和回滚应用程序异常会在抛出业务方法时导致回滚,即使在某些其他位置被捕获也是如此.
您可以使用上下文来确定事务是否标记为回滚.
@Resource
private SessionContext context;
context.getRollbackOnly();
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
207806 次 |
| 最近记录: |