Spring事务管理中的七种传播机制及示例讲解

  • A+
所属分类:Java spring

课程分组的时候分到了Spring传播机制的内容,研究整理了一下。

一、事务传播行为和事务传播机制

事务传播行为:一般发生在事务嵌套的场景中,比如一个有事务的方法里面调用了另外一个有事务的方法

这个时候就会产生事务边界控制的问题,即两个方法是各自作为独立的事务提交还是内层的事务合并到外层的事务一起提交

Spring规定了七大传播机制来解决边界控制的问题。

二、七大传播机制

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

三、对比理解及举例

第一组

传播机制 通俗解释
PROPAGATION_NEVER 强制以非事务的方式运行,外层有事务,将会产生异常
PROPAGATION_MANDATORY 强制加入外层事务,外层没有事务,则会产生异常

Spring事务管理中的七种传播机制及示例讲解

举例:

在充值处理这个业务中,调用了扣款和订单生成两个方法,充值处理业务需要扣款操作和订单生成操作同成功或者失败,所以需要把这两个方法放到同一个事务中运行;所以可以指定这两个方法的传播机制为MANDATORY,这样它们就会都加入到外层事务,处于一个事务中,可以保证同成功或失败。

第二组

传播机制 通俗解释
PROPAGATION_REQUIRED(默认的机制) 需要在事务中执行,外层有事务则加入,没有则自己创建一个事务
PROPAGATION_REQUIRES_NEW 需要在一个新的事务中执行,这个新事务独立于外层事务,互不影响

Spring事务管理中的七种传播机制及示例讲解

举例:

在充值处理这个业务中,新增一个日志记录的功能。日志记录要求充值处理操作成功或者失败都需要执行该方法,日志记录的成功与否也不应该对充值处理的事务造成影响,所以可以将它的传播机制设为REQUIRES_NEW,为其开启一个新的事务,与外层的充值处理的事务独立。

第三组

传播机制 通俗解释
PROPAGATION_SUPPORTS 支持外层,外层有事务就加入,没有就以非事务方式运行
PROPAGATION_NOT_SUPPORTED 以非事务的方式运行,执行的时候先将外层事务挂起,允许外层有事务

Spring事务管理中的七种传播机制及示例讲解

举例:

新增一个短信通知功能,短信通知不涉及数据库的操作,所以不需要事务的支持,可以设置传播机制为NOT_SUPPORTED

PROPAGATION_NESTED

嵌套事务:

  • 它是已经存在事务的一个真正的子事务. 潜套事务开始执行时, 它将取得一个 savepoint。

  • 如果这个嵌套事务失败, 将会回滚到此 savepoint。而不是整个事务的回滚。

区别:前面的3组传播机制中,回滚的单位都是事务,而NESTED支持事务的分割,以savepoint为单位进行回滚。

四、总结

REQUIRES_NEW、NESTED、REQUIRED是最常用的三种传播机制,详细对比一下三者的区别。

方法A中调用方法B

状态 REQUIRES_NEW(两个独立事务) NESTED(B的事务嵌套在A的事务中) REQUIRED(同一个事务)
A异常B正常 A回滚,B正常提交 A与B一起回滚 A与B一起回滚
A正常B异常 B先回滚,A再正常提交 B先回滚,A再正常提交 A与B一起回滚
A正常B正常 B先提交,A再提交 A与B一起提交 A与B一起提交

两两对比

  • NESTED和REQUIRED修饰的内部方法都属于外围方法事务,如果外围方法抛出异常,这两种方法的事务都会被回滚。但是REQUIRED是加入外围方法事务,所以和外围事务同属于一个事务,一旦REQUIRED事务抛出异常被回滚,外围方法事务也将被回滚。而NESTED是外围方法的子事务,有单独的保存点,所以NESTED方法抛出异常被回滚,不会影响到外围方法的事务。

  • NESTED和REQUIRES_NEW都可以做到内部方法事务回滚而不影响外围方法事务。但是因为NESTED是嵌套事务,所以外围方法回滚之后,作为外围方法事务的子事务也会被回滚。而REQUIRES_NEW是通过开启新的事务实现的,内部事务和外围事务是两个事务,外围事务回滚不会影响内部事务。

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: