java Spring事务传播问题
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3573418/
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
Spring Transaction propagation issue
提问by Spiderman
I am using Transaction management with Spring and Hibernate.
My situation is as follow:
I have got bean Awhich is sorrounded by transaction
and it call bean Bwhich is defined with transaction including the attribute 'PROPAGATION_REQUIRED'
我在 Spring 和 Hibernate 中使用事务管理。我的情况如下:
我有一个被事务包围的bean A,它调用 bean B,它用事务定义,包括属性“PROPAGATION_REQUIRED”
B in this case doesn't open new transaction but uses the exsiting one (saw in the logs: 'Participating in existing transaction'). However in case the method in B will throw a runtimeException, on its way back to A it will dirty the transaction and will cause it to be marked for roll-back, even if the external method of A will catch the exception and won't throw it away. I think that this behavior is wrong, in this case I want A to control the transaction and B should not interrupt the transaction in any case.
Is there any way to define B to open transaction if no transaction defined but DO NOTHING if it is already inside an exising transaction and let the upper level make the decision whether to commit or roll-back?
在这种情况下,B 不会打开新交易,而是使用现有交易(在日志中看到:“参与现有交易”)。然而,如果 B 中的方法将抛出一个 runtimeException,在返回 A 的路上它会弄脏事务并导致它被标记为回滚,即使 A 的外部方法将捕获异常并且不会把它扔掉。我认为这种行为是错误的,在这种情况下,我希望 A 控制事务,而 B 在任何情况下都不应该中断事务。
如果没有定义事务,有没有办法定义 B 来打开事务,但如果它已经在现有事务中,则不做任何事情,让上层决定是提交还是回滚?
See more responses about this issue in a thread in Spring community here.
请在此处查看Spring 社区的线程中有关此问题的更多回复。
采纳答案by Sean Patrick Floyd
Theoretically it is possible, but not within the standard means of Spring's Transaction aspects. You would need to create your own aspect that duplicates the spring standard functionality, extending it for your special case. Perhaps it will even be possible to extend the original aspect they use.
理论上是可能的,但不在 Spring 的 Transaction 方面的标准手段之内。您需要创建自己的方面来复制 spring 标准功能,为您的特殊情况扩展它。也许甚至可以扩展他们使用的原始方面。
(Probably you will have to define a custom annotation though, because you can neither override the @Transactional attribute nor extend the Propagation enum.)
(可能您将不得不定义自定义注释,因为您既不能覆盖 @Transactional 属性,也不能扩展 Propagation 枚举。)
Here are some pointers:
以下是一些提示:
- Spring Transaction Management, especially:
- Transaction propagation
- Using @Transactional
- Using @Transactional with AspectJ
Also, you should consider reading the book AspectJ in Action, even if you just want to use Spring AOP, as it gives a very good overview.
此外,即使您只想使用 Spring AOP ,您也应该考虑阅读AspectJ in Action一书,因为它提供了非常好的概述。
A good starting point is to download the sources of the spring-aspects jar, see what they are doing there and provide your own extension of either org.springframework.transaction.aspectj.AbstractTransactionAspector org.springframework.transaction.aspectj.AnnotationTransactionAspect
一个好的起点是下载spring-aspects jar的源代码,查看它们在那里做什么,并提供您自己的扩展org.springframework.transaction.aspectj.AbstractTransactionAspect或org.springframework.transaction.aspectj.AnnotationTransactionAspect
To sum it up: I'm sure it can be done, but it will take a lot of work. The Spring Transaction API is pretty good as it is though. Maybe you should learn to live with it's limitations. If not: start hacking (see above)
总结一下:我相信是可以做到的,但是需要做很多工作。Spring Transaction API 还是很不错的。也许你应该学会忍受它的局限性。如果不是:开始黑客攻击(见上文)
回答by dma_k
It looks like Propagation.NESTEDis something that can help you:
看起来Propagation.NESTED可以帮助您:
- If
Bfails, the transaction started withA(and continued withB) will correctly rolledback to savepoint beforeBis called without touchingA. - When
Bis committed, only savepoint is released, nothing else is issued to DB. Bascailly that means that changes made byBare "merged" into transactionA. - After
Bfinishes, in any above mentioned caseAcan decide weather to continue and commit (that will be a real commit to DB which will include all changes byAandB[if it committed]) or to rollback (that will rollback the transaction up to the state when it was created invalidating all changes byA+B).
- 如果
B失败,以 开始A(并以 继续B)的事务将正确回滚到保存点,然后B在调用之前不触及A。 - 当
B承诺,只保存点被释放,其他什么都颁发给DB。Bascailly 这意味着所做的更改B被“合并”到 transaction 中A。 - 后
B完成,在上述任何情况下,A可以决定天气继续并提交(这将是一个真正的承诺DB,这将包括所有的变化通过A和B[如果犯])或回滚(将回滚事务,直至状态当它被创建时通过A+使所有更改无效B)。
回答by Christophe L
When you configure your Spring transaction manager, you can set the property called "globalRollbackOnParticipationFailure". If set to false, an exception occuring in a method that participates in an existing transaction will no mark the transation for rollback. The transaction is only marked for rollback if the exception if thrown out of the method that started the transaction.
当您配置 Spring 事务管理器时,您可以设置名为“ globalRollbackOnParticipationFailure”的属性。如果设置为 false,则参与现有事务的方法中发生的异常不会将该事务标记为回滚。如果异常从启动事务的方法中抛出,则事务仅标记为回滚。
<bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
<property name="globalRollbackOnParticipationFailure" value="false" />
</bean>
See the JavaDocfor more info.
有关更多信息,请参阅JavaDoc。
回答by bob
Maybe using annotation @Transactional in a way shown below will solve your problem? @Transactional( propagation = Propagation.REQUIRED, noRollbackFor = RuntimeException.class)
也许以下面显示的方式使用注释@Transactional 可以解决您的问题?@Transactional(传播 = Propagation.REQUIRED, noRollbackFor = RuntimeException.class)
回答by gpeche
One solution is to provide TWO bean definitions in your context.xml.
一种解决方案是在您的 context.xml 中提供两个 bean 定义。
One with PROPAGATION_REQUIRED which you will use when you want the bean to be transactional itself
The second with PROPAGATION_SUPPORTS which you will use when you call the bean from inside an existing transaction (Actually, it could even be nontransactional).
一种带有 PROPAGATION_REQUIRED 的,当您希望 bean 本身是事务性的时,您将使用它
第二个带有 PROPAGATION_SUPPORTS ,当您从现有事务内部调用 bean 时将使用它(实际上,它甚至可以是非事务性的)。
If you want to minimise duplication, you can factor common configuration into a parent bean definition.
如果您想最大程度地减少重复,您可以将公共配置考虑到父 bean 定义中。

