【问题标题】:No rollback only for transaction when exception occurs in submethod子方法发生异常时仅对事务不回滚
【发布时间】:2011-05-23 12:13:49
【问题描述】:

我正在使用 Hibernate + spring + @Transactional 注释来处理我的应用程序中的事务。

事务管理器声明如下:

<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
    <property name="sessionFactory" ref="sessionFactory"/>
</bean>

<tx:annotation-driven transaction-manager="transactionManager"/>

这在大多数情况下都很好用,但我发现了一个问题,我有 2 个方法,都注释了 @Transactional:

package temp;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;

public class OuterTestService {
    @Autowired
    private InnerTestService innerTestService;

    @Transactional
    public void outerMethod() {
        try {
            innerTestService.innerTestMethod();
        } catch (RuntimeException e) {
            // some code here
        }
    }
}

package temp;

import org.springframework.transaction.annotation.Transactional;

public class InnerTestService {

    @Transactional
    public void innerTestMethod() throws RuntimeException {
        throw new RuntimeException();
    }
}

当我调用 OuterTestService#outerMethod() 时,我得到一个异常

org.springframework.transaction.UnexpectedRollbackException: Transaction rolled back because it has been marked as rollback-only

由于只有一个事务(没有嵌套事务),整个outerTestMethod() 的事务被标记为仅回滚。

我发现我可以使用 noRollbackFor 轻松克服这个问题:

package cz.csas.pdb.be.service.tempdelete;

import org.springframework.transaction.annotation.Transactional;

public class InnerTestService {

    @Transactional(noRollbackFor = RuntimeException.class)
    public void innerTestMethod() throws RuntimeException {
        throw new RuntimeException();
    }
}

但这必须在每个方法上显式使用。因为在测试(回滚)期间不会引发此错误,所以这是不可接受的。

我的问题——有没有办法自动(例如,不是为每个方法都明确地)设置事务仅在启动事务的方法引发异常时才回滚(在这种情况下,outerTestMethod()) ?

【问题讨论】:

  • 不确定你在期待什么,看看这个(但不认为这是个好主意)static.springsource.org/spring/docs/2.0.0/api/org/…
  • 我希望能够配置事务管理器,使其在发生异常时不会回滚(或标记为仅回滚)事务,除非它发生在启动(或开始的原因)交易。
  • @Transactional 方法调用另一个方法对我来说似乎是个坏消息,好像您并不清楚事务的范围是什么。我会先解决这个问题,不管怎样。
  • 好吧,我需要在两者上都有@Transactional,因为每个都可以直接调用并且我需要它们在事务中。

标签: hibernate spring transactions rollback


【解决方案1】:

创建另一个注释,例如@NoRollbackTransactional,类似:

@Transactional(noRollbackFor = RuntimeException.class)
public @interface NoRollbackTransactional {
}

并在您的方法中使用它。另一方面,我同意Donal 的评论,您应该修改您的事务范围,恕我直言,从另一个@Transactional 调用@Transactional 通常不是一个好主意。

【讨论】:

  • 你是说不支持隔离级别,即 PROPAGATION_REQUIRED(通常是默认值)?
  • 让一个 @Transactional 调用另一个 - 事务通常应该从一个传递到另一个(传播)而不会产生不良影响。当然,您确实会丢失“noRollbackFor”。似乎 Spring Data JPA 经常这样做。
  • 关于“从另一个@Transactional 调用@Transactional 通常不是一个好主意”。我同意乔格的观点。除了调用堆栈中的小开销之外,我不确定问题是什么。如果你可以在没有嵌套的情况下做到这一点。
【解决方案2】:

您可能还需要关闭 globalRollbackOnParticipationFailure

当我在周边交易中进行独立交易时,我遇到了这个问题。当独立事务失败时,周边事务也失败了。

关闭参与标志为我解决了这个问题:

<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
    <property name="globalRollbackOnParticipationFailure" value="false" />
    <property name="sessionFactory" ref="sessionFactory" />
</bean>

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-08-14
    • 2019-08-24
    • 2019-11-19
    • 2021-02-22
    • 2013-10-16
    • 1970-01-01
    相关资源
    最近更新 更多