spring事务PROPAGATION_NESTED 与PROPAGATION_REQUIRES_NEW

1. 什么是嵌套事务PROPAGATION_NESTED

我们回顾下spring 的事务(transaction) 一 基础概念介绍中的PROPAGATION_NESTED概念。

PROPAGATION_NESTED:
嵌套事务呈现父子事务概念,二者之间是有关联的,核心思想就是子事务不会独立提交,而是取决于父事务,当父事务提交,那么子事务才会随之提交;如果父事务回滚,那么子事务也回滚。

与此相反,PROPAGATION_REQUIRES_NEW的内层事务,会立即提交,与外层毫无关联。

但是子事务又有自己的特性,那 就是可以独立进行回滚,不会引发父事务整体的回滚(当然需要try catch子事务,避免异常传递至父层事务,如果没有,则也会引发父事务整体回滚)。
这个特性比较有意思,虽然不能独立提交,但是可以独立回滚,因此,如果存在ABC 三个子事务,那么每个子事务都可以独立回滚,子事务类似一个游戏中的保存点,假设某个时间点,创建了一个保存点A,角色有10发子弹,主线继续发生时,对应执行某个子事务内的逻辑,如果游戏角色打了4发子弹,剩余6发子弹时挂了,点击返回上一个保存点,可以重新玩一次,此时该角色又是10发子弹,对应的就是子事务发生异常,子事务回滚到事务执行之前的那个点,放佛从来没有执行过该子事务一样,数据库的数据也不会发生变更。更重要的是,游戏角色仅会返回到某个进度的保存点,而不是返回到游戏的开始点,否则进度丢了,都想骂人了。

子事务可以独立回滚,也可以通过传递异常,让父事务也回滚,根源在于用户策略,在父事务通过try catch 对子事务进行包裹,灵活策略;

该传播机制的特点是可以保存状态保存点,当前事务回滚到某一个点,从而避免所有的嵌套事务都回滚,即各自回滚各自的,如果子事务没有把异常吃掉,基本还是会引起全部回滚的。

2. PROPAGATION_NESTED 与PROPAGATION_REQUIRES_NEW的区别

PROPAGATION_NESTED 和PROPAGATION_REQUIRES_NEW的区别:
在这里插入图片描述
PROPAGATION_REQUIRES_NEW内层事务执行完就立即提交。

PROPAGATION_NESTED 子事务执行完,不会立即提交,而是等待外层事务完成后一起提交。

2.1 验证PROPAGATION_REQUIRES_NEW内层事务执行完就立即提交

我们复用 spring 的事务(transaction) 三 try catch对事务的影响中的代码,在 “1. 非异常用例”章节中,会分别向2个表里面各自插入一条数据,那么我们通过断点方式,来查看独立事务的提交。

我们在UserServiceImpl中打断点,为了打断点,我们需要增加一行打印,作用是在内层事务执行后打断点:

 System.out.println("addOrder finished");

完整方法代码:

    @Transactional(propagation = Propagation.REQUIRES_NEW)
    @Override
    public void addUser(int id, String name) {
        jdbcTemplate.execute("insert into `student` values (" + id + ",'" + name + "')");

        try {
            //注意:此时有try catch
            orderService.addOrder(3, "110");
            System.out.println("addOrder finished");
        } catch (Exception e) {
            System.out.println(e);
        }


    }

在这里插入图片描述
当代码执行到断点处时,我们看下数据库:
在这里插入图片描述
外层事务未完成提交,未新增了一条数据

内层事务完成提交,新增了一条数据,说明外层和内存是互不影响的

2.2 验证PROPAGATION_NESTED 内层事务执行完未立即提交

我们修改内层事务为PROPAGATION_NESTED 类型,并且也在同样的位置打断点,查看数据库数据是否发生变化。

    @Transactional(propagation = Propagation.NESTED)
    @Override
    public void addOrder(int id, String price) {
        //order是mysql关键词,必须用`(tab键上方的那个键,波浪线键)包裹起来
        jdbcTemplate.execute("insert into `order` values ("+id+",'"+price+"')");
    }

在这里插入图片描述
继续走完父事务的代码,发现,2个数据表都多了一条数据。

从整个例子来看,嵌套子事务是整个事务的一部分,提交时,要随着整体才能提交,但是又可以局部回滚,因此这是PROPAGATION_REQUIRES_NEW等做不到的,PROPAGATION_REQUIRES_NEW会独立提交,不是一个整体的概念。

2.3 验证PROPAGATION_NESTED 内层事务回滚

我们模拟在子事务触发非check异常:

    @Transactional(propagation = Propagation.NESTED)
    @Override
    public void addOrder(int id, String price) {
        //order是mysql关键词,必须用`(tab键上方的那个键,波浪线键)包裹起来
        jdbcTemplate.execute("insert into `order` values ("+id+",'"+price+"')");
        System.out.println( 1/0);
    }

一般在父层有灵活的策略:

        try {
            //注意:此时有try catch
            orderService.addOrder(3, "110");
            System.out.println("addOrder finished");
        } catch (Exception e) {
           // 这个地方,可以做很多事情,比如 ServiceC.methodC();  
        }

在捕获子事务后, 避免异常往上层传递后,这个地方,可以做很多事情,比如 执行ServiceC.methodC(); ,开启另一个子事务,等等。

如果就按照当前的实现的话,子事务会回滚,而父事务顺利提交。
执行结果:
在这里插入图片描述
https://blog.csdn.net/m0_45406092/article/details/119518594

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值