Spring内部事务中的UnexpectedRollBackException(意外回滚异常)

7

我有两个类:

@Service
@Transaction
class A {
    public void method1() {
        private B;

        try {
            save1()
            b.method2()
        } catch (SqlException e) {
            doSomeThing();
        }

       @Autowired
       public setB(){
         this.B = B;
       }
    }
}

@Service
class B {

    @Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception.class)
    public void method2(){
        save2()
        throw new SqlException();
    }

}

我得到了一个预期的 SqlException,但也得到了一个 UnexpectedRollBackException,程序停止了。 我想知道为什么通过 save2() 持久化的数据没有回滚?
这是外部事务的问题吗?
更新:我尝试在 A 类中捕获 UnexpectedRollBackException,一切都正常工作。但我仍然需要一些解释为什么会出现这个异常?我认为当内部事务开始时,外部事务应该被挂起,那么为什么外部事务的回滚对于它来说是意外的?
谢谢。

{btsdaf} - Warren Nocos
2个回答

4
首先:您没有通过Spring将B类的实例注入到A类中。即您的b不受Spring管理,导致这种行为:Spring忽略了方法上的@Transactional注释。
其次,如果您不想在SqlException上回滚,则必须指定noRollbackFor = SqlException.class。
更新:经过澄清,调用发生在托管bean上。但是,预期的行为-事务内部的事务通常不受事务管理系统支持。除非提供该系统的详细信息,否则无法向前迈进。除了内容之外,嵌套事务传播可能更好,然后是REQUIRES_NEW,因为它为外部事务创建了一个回滚点并启动了新事务。

{btsdaf} - hawarden_
@brest1007 但你并没有注入它 - 你是在运行时创建了一个实例,因此没有应用Spring的“魔法”。也就是说,所有的注解都被忽略了。 - Ilya Dyoshin
好的,你很棒。但事实上,我在B中使用了setter注入,但它仍然无法正常工作。当我写问题时,“new”是一个错误。 - hawarden_
你能提供有关事务管理器的信息吗?Spring团队表示,对于REQUIRES_NEW传播中的事务暂停,在运行时有限支持:实际的事务暂停将无法在所有事务管理器上立即生效。这尤其适用于JtaTransactionManager,它需要javax.transaction.TransactionManager在标准Java EE中可用(这是服务器特定的)。 - Ilya Dyoshin
我建议尝试使用嵌套事务传播。实际创建嵌套事务只适用于特定的事务管理器。开箱即用,仅适用于在JDBC 3.0驱动程序上工作时的JDBC DataSourceTransactionManager。一些JTA提供程序可能也支持嵌套事务。 - Ilya Dyoshin

0

我有一个类似的情况,并使用 propagation = Propagation.NESTED 解决了它,这是第二个 method 调用的地方。按照下面提到的方式重写代码并尝试。

@Service
class A {
@Transactional(rollbackFor = { HibernateException.class}, propagation = Propagation.NESTED)
    public void method1() {
        private B;

        try {
            save1()
            b.method2()
        } catch (SqlException e) {
            doSomeThing();
        }

       @Autowired
       public setB(){
         this.B = B;
       }
    }
}

注意:在方法级别上,Transactional 用于具有 propagation nestedclass A。下面显示了 Class B
@Service
class B {

   @Transactional(rollbackFor = {Exception.class}, propagation = Propagation.REQUIRED)
    public void method2(){
        save2()
        throw new SqlException();
    }

}

这在我的情况下解决了问题。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接