Spring七种事务传播行为

事务传播行为

“事务传播行为”描述的是:当一个事务方法被另一个方法调用时,该事务方法如何进行?

是创建新事务?丢弃事务?还是加入到已存在的事务呢?

针对这些情况,Spring框架定义了七种事务传播行为,开发人员可以根据实际的业务场景来选择合适的传播行为。

七种事务传播行为

Spring将其定义在一个枚举类Propagation中,分别如下:

  • REQUIRED
    如果当前没有开启事务,就开启一个新事务,如果当前开启了事务,就加入该事务,默认行为。
  • SUPPORTS
    如果当前开启了事务,就加入该事务,否则非事务执行。
  • MANDATORY
    如果当前开启了事务,就加入该事务,否则抛出异常。说白了,强制事务,不允许非事务执行。
  • REQUIRES_NEW
    始终创建新事务,如果当前开启了事务,则将当前事务挂起。
  • NOT_SUPPORTED
    强制以非事务执行,如果当前开启了事务就将当前事务挂起再执行。
  • NEVER
    非事务执行,如果当前开启了事务则抛出异常。
  • NESTED
    如果当前开启了事务,则在嵌套事务内执行,否则开启一个事务执行。

特别提醒

Spring的事务是基于代理类通过AOP来实现的,如果希望事务传播生效,那么必须通过Spring生成的代理类来调用方法,Spring在增强代理类中判断是否要开启事务,在同一个类中直接调用自身方法Spring是无法帮我们开启事务的!

如下例子,事务传播行为不会生效:
在这里插入图片描述

调用不同的Service,因为调用的代理类,所以事务传播会生效:
在这里插入图片描述

七种传播行为示例

REQUIRED

Spring默认的事务传播行为,也是用的最多的。
如果当前没有开启事务,就开启一个新事务,如果当前开启了事务,就加入该事务,默认行为。

在这里插入图片描述
如上图,save没有开启事务,insert不会回滚,delete开启了事务,delete会回滚。
如果save开启了事务,则delete不会开启新事务,会加入到save的事务中,insert和delete都会回滚。

SUPPORTS

如果当前开启了事务,就加入该事务,否则非事务执行。
在这里插入图片描述
如上图,save没有开启事务,delete也不会开启事务,insert和delete操作均不会回滚。
如果save开启了事务,delete会加入到save的事务中,则insert和delete均会回滚。

MANDATORY

如果当前开启了事务,就加入该事务,否则抛出异常。说白了,强制事务,不允许非事务执行。
在这里插入图片描述
如上图,save没有开启事务,执行delete()时会抛出异常:
在这里插入图片描述
insert成功,delete操作没有执行。
如果save开启了事务,则delete()加入到事务中,不会抛异常。

扫描二维码关注公众号,回复: 8714231 查看本文章

REQUIRES_NEW

如果当前没有开启事务,则开启一个事务,事务的执行。
如果当前开启了事务,则将当前事务挂起,开启一个新事务,事务的执行。
外层事务和内层事务是互相隔离的,内层事务的提交或回滚不影响外层事务,外层事务的提交或回滚也不影响内层事务。

需要捕获内层方法异常,否则内层方法抛异常,会影响外层事务回滚。

在这里插入图片描述
如上图,save开启了事务A,执行delete()时,会将save的事务A挂起,并开启新事务B,delete()执行成功,事务B提交,然后恢复事务A,接着抛出异常,事务A回滚,但是事务B已经提交不会受到影响。
最终delete操作成功,insert操作被回滚。

从控制台的日志也能看见其运行过程:
在这里插入图片描述

NOT_SUPPORTED

强制以非事务执行,如果当前开启了事务就将当前事务挂起再执行。
在这里插入图片描述
如上图,save开启了事务A,执行delete()时会挂起事务A,然后以非事务的方式执行delete并提交,然后恢复事务A,由于save抛出异常,insert回滚。
结果:insert操作回滚,delete操作成功。

NEVER

非事务执行,如果当前开启了事务则抛出异常。
在这里插入图片描述
如上图,由于save开启了事务,导致delete抛出异常:
在这里插入图片描述
如果save没有开启事务,则save和delete都会以非事务执行。

NESTED

如果当前没有开启事务,则开启一个新事务,事务的执行。
否则,在当前事务中以嵌套事务的方式执行。
以嵌套事务执行前,会创建一个保存点savePoint,如果方法异常,则回滚到该savePoint,否则等待和外层事务一起Commit。
在这里插入图片描述

关于Spring的七种事务传播行为都介绍完了,根据实际应用场景选择需要的事务传播行为即可。

REQUIRES_NEW和NESTED的区别

REQUIRES_NEW和NESTED这两种传播行为比较容易搞混,但其实它俩有本质区别。

在当前已经开启事务的情况下:

REQUIRES_NEW会开启一个和外层事务真正隔离的内层事务,内层方法执行完后,内层事务就已经提交或回滚了,和外层事务是完全隔离的,互不影响的。内层事务结束后,才会恢复外层事务,外层事务继续执行。

NESTED本质并没有开启一个新的事务,而是以创建savePoint的方式嵌套的执行,不管内层事务是否回滚或提交,最终都由外层事务来一并执行。

发布了100 篇原创文章 · 获赞 23 · 访问量 9万+

猜你喜欢

转载自blog.csdn.net/qq_32099833/article/details/104010666