场景描述
写这篇博客的缘由是来自工作中的一个场景。公司框架里有日志模块微服务,偶然有一次看到业务模块里面有报错信息,信息内容是日志新增超过了最大自增索引。但业务功能都正常运行,由此引发了我对事务传递机制的兴趣,之前只是为了面试背一背题的我仔细研究了一下。
Spring事务
Spring事务的使用很简单,只需要一个@Transactional注解就可以了,能对大部分的情况实现需要的回滚机制。
注解常用参数简介
rollbackFor
rollbackFor是常用的一个参数,也是alibaba编程规范里面建议我们加上的一个参数。这个注解的作用是指定需要回滚的异常类型。我们都知道出现了异常,报错了才需要回滚,那么什么异常需要回滚呢,就是通过我们这个参数来指定的。
默认情况下,我们回滚的异常是RuntimeException和Error,出现这两个异常或其子类才会回滚我们的代码。这就导致有些异常出现了,但代码却不会回滚,比如常见的IOException。所以建议我们修改这个参数为rollbackFor = Exception.class
propagation
propagation也是常用的一个参数,事务传播机制主要就是由他来控制,他决定了当前方法在被调用时,该怎么处理自己的事务。
这个参数的值总共有七种,
REQUIRED | 如果有事务,那么加入事务,否则新建事务(默认类型) |
SUPPORTS | 其他bean调用这个方法,其他bean有事务,那么就加入事务,其他bean没有事务,那就不用事务 |
MANDATORY | 调用者必须有事务,否则报错 |
REQUIRES_NEW | 不管是否存在事务,都创建一个新的事务,老的挂起,新的执行完毕,继续执行老的事务 |
NOT_SUPPORTED | 不为这个方法开启事务 |
NEVER | 必须在一个没有事务的过程中执行,否则抛出异常 |
NESTED | 如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;如果当前没有事务,则该取值等价于 REQUIRED |
这里面标注的含义是,当我们的方法给propagation参数标记了对应的传播类型后,别的方法来调用我们,我们的事务会出现的情况,会不会加上事务(会不会回滚),会加什么样的事务,都在表格里了。纯粹看文字说明,大家也不太能看得明白,下面我附上一张我自己做的试验图标,标明了在这七种传播类型下,主方法加事务和不加事务,以及异常出现位置,对两个方法产生的影响,在今后的代码编写过程中,切记排坑!
第一行是主方法(调用者)的有无事务栏,第二列是被调用者的传播机制,再附一张我的代码截图,测试的时候是没有加上try catch的,后面测试第三列才加上。
这样大家应该能看明白我的测试思路了,总结一下:
1,只有REQUIRED,REQUIRES_NEW,NESTED能主动给自己加事务;
2,当自己存在事务时,自己报错,一定会回滚;
3,同一个事务,那么就会同时回滚,不同的事务(最后一个嵌套事务除外,嵌套事务主方法回滚,被调用者也会回滚),谁报错,谁回滚;
事务失效
1,相信大家也看出来了,当事务的传播机制变化时,并不是只要加了事务注解就能回滚的,这是其中的一种事务失效方式。
2,当我们的被调用方法跟主方法在同一个类里面时,被调用方法等同于没有加注解,主方法有事务,被调用方法就有事务,且是同一个事务;主方法没事务,被调用方法也就没事务。
注意,经常有人喜欢将代码抽离出来封装成一个方法来调用,在同一个类里面,当封装的方法需要事务的时候,得在调用者那里加事务,加在封装的方法上是没效果的!!!
3,添加了异常处理,try里面的异常就相当于没发生异常,外面的代码发生异常还是能正常回滚的。
参考博客
这12种场景Spring事务会失效!
笔记-事务失效的12种场景