• REQUIRED与REQUIRED_NEW


    出处: https://blog.csdn.net/selfsojourner/article/details/74561745

    spring 事务的传播行为中,有两个容易混淆的行为:REQUIRED和REQURED_NEW。当程序在某些情况下抛出异常时,如果对于这两者不够了解,就可能很难发现而且解决问题。

    下面我们给出三个场景进行分析:

    场景一:

    ServiceA.java:

    public class ServiceA {
        @Transactional
        public void callB() {
            serviceB.doSomething();
        }
    }

    ServiceB.java

    public class ServiceB {
        @Transactional
        public void doSomething() {
            throw new RuntimeException("B throw exception");
        }
    }

     

    这种情况下,我们只需要在调用ServiceA.callB时捕获ServiceB中抛出的运行时异常,则transaction就会正常的rollback。

     

    场景二

    在保持场景一中ServiceB不变,在ServiceA中调用ServiceB的doSomething时去捕获这个异常,如下:

    public class ServiceA {
        @Transactional
        public void callB() {
            try {
                serviceB.doSomething();
            } catch (RuntimeException e) {
                System.err.println(e.getMessage());
            }
        }
    }

     

    这个时候,我们再调用ServiceA的callB。程序会抛出org.springframework.transaction.UnexpectedRollbackException: Transaction rolled back because it has been marked as rollback-only这样一个异常信息。原因是什么呢?

    因为在ServiceA和ServiceB中的@Transactional propagation都采用的默认值:REQUREID。根据我们前面讲过的REQUIRED特性,当ServiceA调用ServiceB的时候,他们是处于同一个transaction中。如下图所示:

    当ServiceB中抛出了一个异常以后,ServiceB会把当前的transaction标记为需要rollback。但是ServiceA中捕获了这个异常,并进行了处理,认为当前transaction应该正常commit。此时就出现了前后不一致,也就是因为这样,抛出了前面的UnexpectedRollbackException。

     

     

    场景三

    在保持场景二中ServiceA不变,修改ServiceB中方法的propagation配置为REQUIRES_NEW,如下:

    public class ServiceB {
        @Transactional(propagation = Propagation.REQUIRES_NEW)
        public void doSomething() {
            throw new RuntimeException("B throw exception");
        }
    }

     

    此时,程序可以正常的退出了,也没有抛出UnexpectedRollbackException。原因是因为当ServiceA调用ServiceB时,serviceB的doSomething是在一个新的transaction中执行的。如下图所示:

    所以,当doSomething抛出异常以后,仅仅是把新创建的transaction rollback了,而不会影响到ServiceA的transaction。ServiceA就可以正常的进行commit。

    当然这里把ServiceA和ServiceB放在两个独立的transaction是否成立,还需要再多多考虑你的业务需求.

  • 相关阅读:
    AndroidStudio制作个人资料界面模块以及SQLite数据库的使用
    掌握这13个MySQL索引知识点,让你面试通过率翻倍
    获取数据表最后最后访问,修改,更新,扫描时间
    一本彻底搞懂MySQL索引优化EXPLAIN百科全书
    Win10系统下的MySQL5.7.24版本(解压版)详细安装教程
    解决beego在ubuntu下连接mysql与重置mysql密码
    在Windows上安装MySQL
    docker~dockertoolbox的加速器
    Git 安装 on centos7
    centos7.x中安装SQL Server
  • 原文地址:https://www.cnblogs.com/But-you/p/10489431.html
Copyright © 2020-2023  润新知