Java 事务标记为仅回滚:如何找到原因
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/19302196/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Transaction marked as rollback only: How do I find the cause
提问by Vojtěch
I am having issues with committing a transaction within my @Transactional method:
我在 @Transactional 方法中提交事务时遇到问题:
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
当我从 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()...
- The context of methodB is completely missing in the exception - which is okay I suppose?
- 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.
- 异常中完全缺少 methodB 的上下文 - 我想这可以吗?
- methodB() 中的某些内容将事务标记为仅回滚?我怎样才能找到它?例如,有没有一种方法可以检查类似的东西
getCurrentTransaction().isRollbackOnly()?
- 像这样我可以逐步完成该方法并找到原因。
采纳答案by Vojtěch
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.
发生的情况是,即使methodB
有正确的注释,methodC
也没有。当抛出异常时,第二个@Transactional
事务只将第一个事务标记为回滚。
回答by Mareen
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();
回答by Ean V
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
,方法中发生的任何异常都会将周围的 TX 标记为仅回滚(即使您捕获它们)。您可以使用@Transactional
注释的其他属性来防止它回滚,例如:
@Transactional(rollbackFor=MyException.class, noRollbackFor=MyException2.class)
回答by rémy
disable the transactionmanager in your Bean.xml
禁用 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 ;)
注释掉这些行,您将看到导致回滚的异常;)
回答by FelixJongleur42
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.
并在堆栈中上升,通常到某个拦截器。在那里您可以从某个 catch 块中读取导致异常的信息。
回答by Kumaresan Perumal
I struggled with this exception while running my application.
我在运行我的应用程序时遇到了这个异常。
Finally the problem was on the sql query. i mean that the query is wrong.
最后问题出在 sql 查询上。我的意思是查询是错误的。
please verify your query. This is my suggestion
请验证您的查询。这是我的建议
回答by aquajach
Found a good explanation with solutions: https://vcfvct.wordpress.com/2016/12/15/spring-nested-transactional-rollback-only/
找到了一个很好的解决方案解释: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.
1) 如果它并不真正需要事务控制,则从嵌套方法中删除 @Transacional。所以即使它有异常,它也只是冒泡,不会影响事务性的东西。
OR:
或者:
2) 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.
2)如果嵌套方法确实需要事务控制,则将其设置为传播策略的REQUIRE_NEW,这样即使抛出异常并标记为仅回滚,调用者也不会受到影响。
回答by Asif Raza
apply the below code in productRepository
在 productRepository 中应用以下代码
@Query("update Product set prodName=:name where prodId=:id ")
@Transactional
@Modifying
int updateMyData(@Param("name")String name, @Param("id") Integer id);
@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
而在junit测试中应用下面的代码
@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
它适用于我的代码