我正在使用DB2数据库并测试了以下代码:
无论methodB是否具有Propagation.REQUIRES_NEW,无论methodB是否具有异常,方法A的结果都将正确提交。

这违反了我的假设,必须使用Propagation.REQUIRES_NEW来实现这一目标。

        ClassA
            @Autowire
            private ClassB classB;

            @Transactional
            methodA(){
                ...
                try{
                     classB.methodB();
                }catch(RuntimeException ex){
                     handleException(ex);
                }
                ...
            }

        ClassB
            @Transactional(propagation = Propagation.REQUIRES_NEW)
            methodB(){...}




感谢@Kayaman,我想我现在已经知道了。

我看到的行为是因为methodB的@Transactional注释不起作用,因此methodB被视为没有任何事务注释的普通函数。

出现问题的地方是在methodA中,我通过super.methodB()从ClassB的子类中调用methodB,并认为它将提供事务性methodB,但该方法不起作用:

    @Service
    @Primary
    ClassC extends ClassB{
        @override
        methodB(){
            super.methodB();
        }
    }


我知道,如果您从同一类的另一个非事务方法中调用事务方法,则事务注释将不起作用。

不知道super.methodB()也会因为相同的原因而失败(任何人都可以提供更多的解释吗?)



总之,在第一段代码的示例中,当methodB具有RuntimeException时,

如果methodB具有NO transaction批注:A和B共享同一笔交易; methodA不会回滚

如果methodB具有REQUIRED注释:A和B共享同一笔交易; methodA将回滚

如果methodB具有REQUIRES_NEW注释:A和B具有独立的事务; methodA不会回滚

最佳答案

如果没有REQUIRES_NEW(即默认的REQUIRED或行为类似的其他一个),则ClassB.methodB()参与与ClassA.methodA()相同的事务。 methodB()中的异常将标记该事务回滚。即使您捕获到异常,事务也会回滚。

使用REQUIRES_NEW,回滚的事务将特定于methodB(),因此当您捕获异常时,仍然存在健康的原始非回滚事务。



ClassA
@Transactional
methodA(){
    try{
         classB.methodB();
    }catch(RuntimeException ex){
         handleException(ex);
    }
}

ClassB
@Transactional
methodB(){
    throw new RuntimeException();
}


上面的代码将回滚整个事务。对于propagation=TransactionPropagation.REQUIRES_NEW,使用methodB()不会。

如果没有对methodB()的任何注释,则在methodA()级别上只有一个tx边界,Spring不会意识到抛出了异常,因为它被捕获在方法的中间。这类似于将methodB()的内容内联到methodA()。如果该异常是非数据库异常(例如NullPointerException),则事务将正常提交。如果该异常是数据库异常,则将基础数据库事务设置为回滚,但是Spring不会意识到这一点。然后Spring尝试提交,并抛出一个UnexpectedRollbackException,因为数据库不允许提交tx。

显式或意外地省略注释是错误的。如果打算执行db操作,则必须使用定义良好的事务上下文,并且知道您的传播。

调用super.methodB()会绕过Spring的常规代理机制,因此,即使有注释,也会被忽略。最后,对我来说,调用super.methodB()似乎是一种设计气味。使用继承来减少行数通常是不好的做法,在这种情况下会导致严重的错误。

关于java - 子函数中的RuntimeException不应影响父调用函数-REQUIRES_NEW是否起作用?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/60985423/

10-11 01:32