在子方法中发生异常时,不会仅为事务回滚

Ond*_*cka 6 spring hibernate transactions rollback

我正在使用Hibernate + spring + @Transactionalannotations来处理我的应用程序中的事务.

事务管理器声明如下:

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

<tx:annotation-driven transaction-manager="transactionManager"/>
Run Code Online (Sandbox Code Playgroud)

这在大多数情况下效果很好,但是我发现了一个问题,我有两种方法,都注释了@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
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

package temp;

import org.springframework.transaction.annotation.Transactional;

public class InnerTestService {

    @Transactional
    public void innerTestMethod() throws RuntimeException {
        throw new RuntimeException();
    }
}
Run Code Online (Sandbox Code Playgroud)

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

org.springframework.transaction.UnexpectedRollbackException: Transaction rolled back because it has been marked as rollback-only
Run Code Online (Sandbox Code Playgroud)

由于只有一个事务(没有嵌套事务),整个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();
    }
}
Run Code Online (Sandbox Code Playgroud)

但是必须在每种方法上明确使用它.因为在测试期间(滚动)不会引发此错误,所以这是不可接受的.

我的问题 - 是否有一种方法可以自动(例如,不明确地为每个方法设置)只有当从启动事务的方法(在这种情况下,outerTestMethod())中引发异常时才会回滚事务?

aba*_*ogh 11

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

@Transactional(noRollbackFor = RuntimeException.class)
public @interface NoRollbackTransactional {
}
Run Code Online (Sandbox Code Playgroud)

并在你的方法上使用它.另一方面,我同意Donal的评论,你应该修改你的交易范围,@Transactional从另一方面调用通常不是一个好主意@Transactional.

  • 让一个@Transactional调用另一个 - 事务通常应该从一个传递到另一个(传播)而不会产生不良影响.当然,你确实失去了"noRollbackFor".看起来像Spring Data JPA经常这样做. (4认同)

jas*_*sop 5

您可能还需要关闭globalRollbackOnParticipationFailure.

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

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

<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
    <property name="globalRollbackOnParticipationFailure" value="false" />
    <property name="sessionFactory" ref="sessionFactory" />
</bean>
Run Code Online (Sandbox Code Playgroud)