Spring事务传播问题

时间:2010-08-26 08:38:26

标签: java hibernate spring transactions

我正在使用Spring和Hibernate进行事务管理。 我的情况如下:
我有豆 A ,它受到交易的影响 它调用bean B ,它是用事务定义的,包括属性'PROPAGATION_REQUIRED'

在这种情况下,

B不会打开新事务,而是使用现有事务(在日志中看到:'参与现有事务')。但是,如果B中的方法将抛出一个runtimeException,在返回A的过程中它会弄脏事务并导致它被标记为回滚,即使A的外部方法将捕获异常而不会把它扔掉。我认为这种行为是错误的,在这种情况下我希望A控制事务,B不应该在任何情况下中断事务。
如果没有定义事务,有没有办法定义B来打开事务,但是如果它已经在一个exising事务中并且让上层决定是提交还是回滚,那么是否有任何方法?

在Spring社区here的帖子中查看有关此问题的更多回复。

5 个答案:

答案 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.AbstractTransactionAspectorg.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定义。