我正在使用Spring和Hibernate进行事务管理。
我的情况如下:
我有豆 A ,它受到交易的影响
它调用bean B ,它是用事务定义的,包括属性'PROPAGATION_REQUIRED'
B不会打开新事务,而是使用现有事务(在日志中看到:'参与现有事务')。但是,如果B中的方法将抛出一个runtimeException,在返回A的过程中它会弄脏事务并导致它被标记为回滚,即使A的外部方法将捕获异常而不会把它扔掉。我认为这种行为是错误的,在这种情况下我希望A控制事务,B不应该在任何情况下中断事务。
如果没有定义事务,有没有办法定义B来打开事务,但是如果它已经在一个exising事务中并且让上层决定是提交还是回滚,那么是否有任何方法?
在Spring社区here的帖子中查看有关此问题的更多回复。
答案 0 :(得分:5)
看起来Propagation.NESTED
可以帮助您:
B
失败,则以A
(并继续B
)开始的事务将在调用B
之前正确回滚到保存点,而不会触及A
B
时,仅释放保存点,不向DB发出任何其他内容。 Bascailly意味着B
所做的更改已“合并”到交易A
中。B
完成后,在任何上述情况A
可以决定天气继续并提交(这将是对DB的真实提交,其将包括A
和{B
之后的所有更改{1}} [如果已提交])或回滚(这会将事务回滚到创建时的状态,使A
+ B
的所有更改无效。答案 1 :(得分:5)
配置Spring事务管理器时,可以设置名为" globalRollbackOnParticipationFailure "的属性。如果设置为false,则参与现有事务的方法中发生的异常将不会标记要回滚的转换。如果异常被抛出启动事务的方法,则事务仅标记为回滚。
<bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
<property name="globalRollbackOnParticipationFailure" value="false" />
</bean>
有关详细信息,请参阅JavaDoc。
答案 2 :(得分:3)
理论上它是可能的,但不是Spring的交易方面的标准方法。您需要创建自己的方面,复制弹簧标准功能,并根据您的特殊情况进行扩展。也许甚至可以扩展他们使用的原始方面。
(可能你必须定义一个自定义注释,因为你既不能覆盖@Transactional属性也不能扩展传播枚举。)
以下是一些提示:
此外,您应该考虑阅读本书AspectJ in Action,即使您只是想使用Spring AOP,因为它提供了非常好的概述。
一个很好的起点是下载sources of the spring-aspects jar,看看他们在那里做了什么,并提供自己的org.springframework.transaction.aspectj.AbstractTransactionAspect
或org.springframework.transaction.aspectj.AnnotationTransactionAspect
总结一下:我确信它可以做到,但需要做很多工作。尽管如此,Spring Transaction API非常好用。也许你应该学会忍受它的局限性。如果不是:开始黑客攻击(见上文)
答案 3 :(得分:0)
也许以下面显示的方式使用注释@Transactional可以解决您的问题? @Transactional(propagation = Propagation.REQUIRED,noRollbackFor = RuntimeException.class)
答案 4 :(得分:0)
一种解决方案是在context.xml中提供两个bean定义。
一个PROPAGATION_REQUIRED,当您希望bean本身为交易时,您将使用
第二个PROPAGATION_SUPPORTS,当您从现有交易中调用bean时,您将使用它(实际上,它甚至可能是非交易的)。
如果要最小化重复,可以将常用配置纳入父bean定义。