内层事务方法try catch了,当内部抛出异常回滚,会触发外部事务回滚

场景:接口A的方法A1,接口B的方法B1,都添加了事务的注解,接口A的方法A1先修改数据库,之后再调用接口B的方法B1,其中调用方法B1有try catch捕获异常,但是不往外抛异常,那此时如果方法B1有一场了,那会触发方法A中修改数据的操作吗?答案是会触发,当前此前提的基础是用的是 @Transactional 注解,并且采用的是默认的事务

1、例子

(1)例子的单元测试

@SpringBootTest
@RunWith(SpringJUnit4ClassRunner.class)
public class TransactionalTest {

   @Resource
   SecondService secondService;
   @Test
    public void test(){
       User user = new User();
       user.setId(1L);
       user.setName("2222");
       Long isSuc= secondService.update(user);
       Assert.assertEquals(1,isSuc.intValue());
   }
}

(2)接口和实现类

类A

public interface SecondService {
    Long update(User user);
}

@Service("secondService")
public class SecondServiceImpl implements SecondService {
    @Resource
    FirstService firstService;
    @Resource
    FirstDao firstDao;
    @Transactional(rollbackFor = RuntimeException.class)
    @Override
    public Long update(User user) {
        firstDao.update(user);
        //这是为了能修改id=2的数据
        user.setId(user.getId()+1);
        try {
            firstService.update(user);
        }catch (Exception e){
            System.out.println("系统抛出异常");
        }
        return null;
    }
}    

类B

public interface FirstService {
    /**
     * 修改用户数据
     * @param user
     * @return
     */
    Long update(User user);
}

@Service("firstService")
public class FirstServiceImpl implements FirstService {
    @Resource
    FirstDao firstDao;
   
    @Transactional
    @Override
    public Long update(User user) {
        Long isSuc=firstDao.update(user);
        if(isSuc==1){
            throw new RuntimeException();
        }
        return isSuc;
    }
}

(3)数据库User表数据

在这里插入图片描述

2、执行单测的结果

(1) 假想的结果

(1) 应该是既然内部事务被try catch了,那内部出现异常回滚,应该不会触发外部事务回滚,这样应该是id=1的数据被修改了。而id=2的数据被回滚了,相当于没有修改,
(2) 默认的注解型事务类型是Propagation.REQUIRED,你可能会想两个事务合并,取大,之后相当于类A的方法上加事务,类B上的方法就不用加事务,类B的方法发生异常,try catch后就不会触发外部的事务
最后的数据库结果就像下面图片那样
在这里插入图片描述

(2)程序实际执行的结果

id=1和id=2的数据都没有被修改,都被回滚了,像下图片一样
在这里插入图片描述

3、 原因

首先注解型事务默认的事务类型是Propagation.REQUIRED 没错的
下面是图片的源码:
在这里插入图片描述
网上也有很多讲此类型事务的,大概是:如果有事务,那么加入事务,没有的话新建一个
这里要注意一个关键字:
这里加入事务不是说两个事务合并在一起,看一下下面的截图
在这里插入图片描述

我在32行debug了一下,这时候如果按原来的说法,两个事务合成一个,那就不应该会在32行停住,控制台也打印出了catch里的内容,我有debug了一下,看到在这里插入图片描述
之后又分别看了一下doSetRollbackOnly()doRollback(),
在这里插入图片描述
说明子类负责实现执行逻辑,但是通过注释,也知道doRollback才是执行回滚的,doSetRollbackOnly需要打上标记,这样当外部事务触发时通过标记得到需不需要外部事务一起回滚。
这里需要注意的是: catch里面的输出是会执行的,
当内部事务结束后,外部事务会走doRollback()方法,并执行下面图片的操作
在这里插入图片描述
等外部事务结束就整个流程结束了

之后再知乎上搜索到了RCA: Spring 事务 rollback-only异常,可以看一下

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值