一文看懂Spring事务传播机制

所谓事务的“传播”指的是多个包含事务的方法互相调用时,事务是如何传播的。

本文首先介绍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的七种事务传播方式

事务传播行为类型说明
PROPAGATION_REQUIRED如果当前没有事务,就新建一个事务,如果已经存在一个事务中,加入到这个事务中。这是最常见的选择。
PROPAGATION_SUPPORTS支持当前事务,如果当前没有事务,就以非事务方式执行。
PROPAGATION_MANDATORY使用当前的事务,如果当前没有事务,就抛出异常。
PROPAGATION_REQUIRES_NEW新建事务,如果当前存在事务,把当前事务挂起。
PROPAGATION_NOT_SUPPORTED以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
PROPAGATION_NEVER以非事务方式执行,如果当前存在事务,则抛出异常。
PROPAGATION_NESTED如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与PROPAGATION_REQUIRED类似的操作。

链接: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事务传播示例

  • 4
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值