spring 事务嵌套异常:Transaction rolled back because it has been marked as rollback-only

首先我先把原因抛出来(看得懂这个的话,就不用看下面了):

原因:在使用Spring注解@Transactional(默认传播机制:外层有事务,则沿用外层事务;否则创建新事务)时,存在嵌套事务,即存在“外层”事务调用“内层”事务,并且在调用时catch住了内层异常,没有抛出异常。此时外层事务执行commit时,事务已在内层异常时被至为rollback,所以Spring会抛出“Transaction rolled back because it has been marked as rollback-only”

 

还是不太懂的话,我将流程图和细节拆分下,再用例子帮助理解:

流程图:

spring 事务嵌套异常:Transaction rolled back because it has been marked as rollback-only_第1张图片

例子:

// 伪代码
@Service
class ServiceA{

    @Autowired
    ServiceB serviceB;

    @Transactional
    public void method() {
        // ...执行自身业务...

        try {
            //调用ServiceB方法
            serviceB.method();
        } catch (Exception e) {
            //没有继续抛出
        }
        
        // ...执行别的业务...
    }
}

@Service
class ServiceB{

    @Transactional
    public static void method() {
        // 异常代码
        int i = 1/0;
    }
}

在上面的例子中,ServiceB在执行method方法,出现异常时,已将事务标志为rollback。而ServiceA捕获了ServiceB的异常,并且没有继续抛出,当ServiceA执行完自身全部业务,准备commit事务时,检查发现事务已被标志为rollback。则不予commit,并且抛出异常:“Transaction rolled back because it has been marked as rollback-only”

 

Spring源码(版本4.3.18):

在ServiceB发生异常,事务回滚时:

spring 事务嵌套异常:Transaction rolled back because it has been marked as rollback-only_第2张图片

ServiceA执行commit时,发生异常

spring 事务嵌套异常:Transaction rolled back because it has been marked as rollback-only_第3张图片

 

解决方法:

既然已经知道原因了,解决起来就很简单了

1.在不影响业务的前提下,去除内层或者外层事务

2.更改内层事务传播机制,如:REQUIRES_NEW等

 

加餐:

有同学说:不会啊,我用嵌套发生同样的情况也不会抛异常啊

没问题的同学相信你是这么做的

// 伪代码
@Service
class Service{

    @Transactional
    public void method1() {
        // ...执行自身业务...

        try {
            //调用method2()方法
           method2();
        } catch (Exception e) {
            //没有继续抛出
        }
        
        // ...执行别的业务...
    }

    @Transactional
    public void method2(){
        int i = 1/0;
    }
}

本质区别在于:method1调用了同一个类的方法method2。

原因:因为注解的生效是通过代理模式实现的,同一个类下相互调用,被调用者是没法生成代理方法的(具体原因不是本文重点,不做展开解释),即method2的事务根本就没有生效。所以也不会出现异常。

不过上面Service类自己注入自己,并且用service.method2调用的话,也可以生效(具体也不做展开解释)

 

以上为本文全部内容,希望对同行业的朋友们有所帮助~感谢阅读

你可能感兴趣的:(spring 事务嵌套异常:Transaction rolled back because it has been marked as rollback-only)