一文看懂Spring事务传播机制
所谓事务的“传播”指的是多个包含事务的方法互相调用时,事务是如何传播的。
本文首先介绍Spring中的七种事务传播方式,然后针对每一种传播方式举例进行讲解,看完就能完全理解Spring的事务传播机制。
目录
REQUIRED
例1 内外层都有事务
例2 外层无事务,内层有事务,内层抛错
例3 外层有事务,内层无事务,内层抛错
例4 外层有事务,内层抛错catch
SUPPORTS
例1 内外层有事务,内层抛异常
例2 内外层有事务,内层抛异常,外层try/catch
MANDATORY
例1 外层无事务,直接抛错
例2 外层有事务,内层抛错,外层catch
REQUIRED_NEW
例1 内外层有事务,内层抛错,外层catch
例2 内外层有事务,外层抛错
NOT_SUPPORTED
例1 外层有事务注解,内层抛错
NEVER
例1 外层有事务,直接抛错
NESTED
例1 内外层有事务,内层抛错
例2 外层抛错
例3 内层抛错,外层catch
Spring的七种事务传播方式
链接:https://juejin.cn/post/6844903566205779982 |
光看这些枯燥的文字实在难以理解,接下来我会针对每种传播进行举例说明
首先创建一个简单的数据库表。这个表只有2条数据,分别对应2个用户Tom和Jerry,在初始状态他们各自都有100块。
REQUIRED
这是Spring默认的事务传播机制,也就是当我们在某一个方法上直接使用@Transaction注解的时候,默认的使用此种事务传播。下面举例说明。
例1 内外层都有事务
篮框的方法updateMoney1作为外层方法,首先去更新Tom的余额,然后调用绿框中的updateJerryMoney1内层方法,尝试更新Jerry的余额。两个方法都使用了@Transaction注解。让内层方法主动抛出异常。(特别提醒,因为两个方法在一个类中,为了让事务生效,需要将类再次注入进来,如红框所示)
调用controller接口:
接口抛错:
结果:查看数据库中数据,余额均回滚。
解析:外层方法和内层方法都在一个事务中,内层方法抛错后,两个方法均会回滚。
例2 外层无事务,内层有事务,内层抛错
结果:外层提交内层回滚。
解析:因为外层无事务,只有内层有事务,内层抛错只会回滚内层事务。
例3 外层有事务,内层无事务,内层抛错
结果:内外层均回滚。
解析:虽然内层没有加事务,但确实触发了事务。这里如果不想让内层方法跟着回滚,可以在内层使用NOT_SUPPORTED传播。如果这里换成外层抛错,还是内外层均回滚。原理一样。
例4 外层有事务,内层抛错catch
结果:内外层均提交。
解析:因为错误没有抛出,事务未触发。
SUPPORTS
见名知意,如果有事务就加入,否则不开启事务。
例1 内外层有事务,内层抛异常
结果:内外层均回滚。
解析:内外层在同一个事务中,异常导致二者均回滚。
例2 内外层有事务,内层抛异常,外层try/catch
结果:内外层均回滚。
解析:这里需要注意,内层已经触发了事务,因为内外层在同一个事务中,即便外层catch了异常,依旧会一起回滚。
MANDATORY
强制要求必须有事务,不然抛错。
例1 外层无事务,直接抛错
例2 外层有事务,内层抛错,外层catch
结果:内外层均回滚。
解析:即便外层catch了异常,但是内外层在同一事务中,依旧会回滚。
REQUIRED_NEW
例1 内外层有事务,内层抛错,外层catch
结果:外层提交,内层回滚。
解析:内外层分别在各自的事务中,互不干预,内层触发事务则内层回滚。外层catch了异常未抛出,则不会触发事务。如果外层没有catch,则外层也会回滚,不过需要注意的是这里是2个事务。
例2 内外层有事务,外层抛错
结果:外层回滚,内层提交。
解析:外层触发事务回滚,不影响内层。
NOT_SUPPORTED
非事务方式执行,不管当前在不在事务中。
例1 外层有事务注解,内层抛错
结果:外层回滚,内层提交。
解析:内层不支持事务,即便抛错也不回滚;抛错到外层,外层触发事务,回滚。
NEVER
和mandatory相反,如果当前存在事务则抛出异常。
例1 外层有事务,直接抛错
NESTED
当前有事务则嵌套事务,也就是创建一个子事务;当前没事务则和Required相同。这应该是最让人迷惑的事务传播了。
例1 内外层有事务,内层抛错
结果:内外层均回滚 。
解析:看起来和required_new是一样的。这里要注意,经常看到一种说法是子事务不影响父事务,这样说是不严谨的。内层事务抛异常,触发内层事务回滚,异常又被外层捕获,再次触发事务回滚。
例2 外层抛错
结果:内外层均回滚。
解析:主事务会影响嵌套的子事务,二者均回滚。这和Required_new是不一样的。
例3 内层抛错,外层catch
结果:外层提交,内层回滚。
解析:内层的嵌套子事务在这种情况下不会影响外层。注意这里和Required是不同的,required的话外层也会回滚。
Gitee代码链接在此 SpringTransactionPropagation: Spring事务传播示例
你转转你那脑子吧: 好呢好呢
艾-普-西-隆: 第一次是的。因为微博登陆强制要求输入验证码或私信或扫码。其实和微信差不多:都是手机端应用,登陆都需要用到手机。
艾-普-西-隆: 这个文章写在2021年,现在已经不适用了。
你转转你那脑子吧: 博主你好,最近微博政策有新的变化,登录需要按顺序点击对应图片,这个还能用一般的方法实现吗?
csdn565973850: 我看到你的模拟登录还是需要手动输入短信验证码或者手动点击APP推送消息,这样还算是模拟登录吗。在程序跑的时候还要自己时刻关注手机等着输入验证码吗