• spring事务传播的Propagation.REQUIRES_NEW以及NEVER MANDATORY验证,及其失效的诡异问题


    NEVER

    不使用事务,如果当前事务存在,则抛出异常

    验证:

    复制代码
    @Service
    public class PrService {
        @Autowired
        PrDao dao;   
        @Transactional
        public void savea() {
            dao.a();//保存第一条数据
            saveb();
        }
        @Transactional(propagation = Propagation.NEVER)
        private void saveb() {
            dao.b();//保存第二条数据
            int i=1/0;
        }
    }
    复制代码

    写一个controller调用这个savea方法,页面看到的是/ by zero,数据库中两条数据都没有插入进去,都回滚了。照说设置了Propagation.NEVER,应该saveb方法根本执行不了,报never的错。为什么执行了呢?

    因为是直接调用的saveb(),不是从代理对象上调用的方法,改成这样:

    复制代码
    @Service
    public class PrService {
        @Autowired
        PrDao dao;
        
        @Autowired
        PrService prService;
        
        @Transactional
        public void savea() {
            dao.a();//保存第一条数据
            prService.saveb();
        }
    
        @Transactional(propagation = Propagation.NEVER)
        private void saveb() {
            dao.b();//保存第二条数据
            int i=1/0;
        }
    }
    复制代码

    注意这里是  prService.saveb()和前面不同,但是居然在  dao.b(); 这一行报了一个空指针的错误,这就诡异了,这个dao明明在上面的savea方法里面还有值的,你知道是为什么吗?

    原来saveb方法的修饰符是private,导致代理对象无法继承这个方法。改成public

    public void saveb()

    再次测试,看到期待的报错了:

    Existing transaction found for transaction marked with propagation 'never'

     

     

    MANDATORY

    当前存在事务,则加入当前事务,如果当前事务不存在,则抛出异常。

    这里把MANDATORY放在saveb方法上,就要把savea方法上的transactional注解去掉,才能看到报错。

    复制代码
    @Service
    public class PrService {
        @Autowired
        PrDao dao;
        
        @Autowired
        PrService prService;
    
        public void savea() {
            dao.a();//保存第一条数据
            prService.saveb();
        }
    
        @Transactional(propagation = Propagation.MANDATORY)
        public void saveb() {
            dao.b();//保存第二条数据
        }
    }
    复制代码

    或者直接把MANDATORY放在a方法上也会报错:

    复制代码
    @Service
    public class PrService {
        @Transactional(propagation = Propagation.MANDATORY)
        public void savea() {
        }
    }
    复制代码

    报错如下

    No existing transaction found for transaction marked with propagation 'mandatory'

     

    REQUIRES_NEW

    创建一个新事务,如果存在当前事务,则挂起该事务。

    可以理解为设置事务传播类型为REQUIRES_NEW的方法,在执行时,不论当前是否存在事务,总是会新建一个事务。

    现在写一个demo验证,savea方法调用saveb方法,希望saveb方法里面异常了且事务回滚,savea方法里面不回滚

    下面验证:

    同样为了在避免事务失效,在代理对象上调用方法,将被调用的方法放到一个单独的类中:

    复制代码
    @Service
    public class PrService {
        @Autowired
        PrDao dao;
    
        @Autowired
        SaveBService saveBService;
    
        @Transactional
        public void savea() {
            dao.a();//插入第一条数据
            saveBService.saveb();
        }
    }
    复制代码
    复制代码
    @Service
    public class SaveBService {
        @Autowired
        PrDao dao;
    
        @Transactional(propagation = Propagation.REQUIRES_NEW)
        public void saveb() {
            dao.b();//插入第二条数据
            int i = 1/0;
        }
    }
    复制代码

    这里PrService的savea方法调用SaveBService的saveb方法,写一个controller访问savea方法,页面看到一个异常 / by zero,再检查数据库,两条数据都有没有插入进去。这是为什么呢?看上去第二个方法已经写到独立的类中了。

    原来是因为saveb方法抛出的异常savea方法没有捕获,又抛出去了,当然要回滚了。写个try catch就行:

    复制代码
        @Transactional
        public void savea() {
            dao.a();//插入第一条数据
            try {
                saveBService.saveb();
            }catch (Exception e) {
                System.out.println("some error");
            }
        }
    复制代码

    再次测试,第二条数据没有插入,第一条数据插入到数据库了,页面也看不到报错了。

     
  • 相关阅读:
    SpringCloud--Nacos解析
    python强制停止线程学习
    知名药企集中签约阿里健康,数字化健康服务成进博会热议话题
    (四) ES6 新特性 —— 参数默认值与spread扩展运算符
    【Redis面试题(46道)】
    typeof 与 instanceof 区别
    使用PHP编写采集药品官方数据的程序
    Shell 函数详解(函数定义、函数调用)
    JAVA计算机毕业设计宠物领养系统Mybatis+系统+数据库+调试部署
    limit 用法
  • 原文地址:https://www.cnblogs.com/gong2021/p/17382817.html