说一下 Spring 事务传播机制?

1.什么是 Spring 事务传播机制?

Spring 事务传播机制是指,包含多个事务的方法在相互调用时,事务是如何在这些方法间传播的。

既然是“事务传播”,所以事务的数量应该在两个或两个以上,Spring 事务传播机制的诞生是为了规定多个事务在传播过程中的行为的。

比如方法 A 开启了事务,而在执行过程中又调用了开启事务的 B 方法,那么 B 方法的事务是应该加入到 A 事务当中呢?

还是两个事务相互执行互不影响,又或者是将 B 事务嵌套到 A 事务中执行呢?

所以这个时候就需要一个机制来规定和约束这两个事务的行为,这就是 Spring 事务传播机制所解决的问题。

2.Spring 事务传播机制有哪些?

Spring 事务传播机制可使用 @Transactional(propagation=Propagation.REQUIRED) 来定义,Spring 事务传播机制的级别包含以下 7 种:

Propagation.REQUIRED:默认的事务传播级别,它表示如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。


Propagation.SUPPORTS:如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。


Propagation.MANDATORY:(mandatory:强制性)如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。


Propagation.REQUIRES_NEW:表示创建一个新的事务,如果当前存在事务,则把当前事务挂起。也就是说不管外部方法是否开启事务,Propagation.REQUIRES_NEW 修饰的内部方法会新开启自己的事务,且开启的事务相互独立,互不干扰。
Propagation.NOT_SUPPORTED:以非事务方式运行,如果当前存在事务,则把当前事务挂起。


Propagation.NEVER:以非事务方式运行,如果当前存在事务,则抛出异常。


Propagation.NESTED:如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;如果当前没有事务,则该取值等价于 PROPAGATION_REQUIRED。


以上 7 种传播机制,可根据“是否支持当前事务”的维度分为以下 3 类:

a687fdab9f614e988b2eaf36e35e9d77.png
看到这里,有人可能会说:说了这么多,我也看不懂啊,即使看懂了,我也记不住啊?这要咋整? 

没关系,接下来我们用一个例子,来说明这 3 类事务传播机制的区别。

以情侣之间是否要买房为例,我们将以上 3 类事务传播机制可以看作是恋爱中的 3 类女生类型:

普通型
强势型
懂事型


这三类女生如下图所示:

dfc6ce38571941fea17dd6a58fe5d9ae.png
支持当前事务的“女生”,这里的事务指的是“房子”,它分为 3 种(普通型女生): 

Propagation.REQUIRED(需要有房子):有房子了咱们一起住,没房子了咱们一起赚钱买房子。


Propagation.SUPPORTS(可以有房子):有房子了就一起住,没房子了咱们就一起租房子。


Propagation.MANDATORY(强制有房子):有房子了就一起住,没房子了就分手。


不支持当前事务的“女生”也分为 3 种(强势型或者叫事业型):

Propagation.REQUIRES_NEW:不要你的房子,必须一起赚钱买房子。


Propagation.NOT_SUPPORTED:不要你的房子,必须一起租房子。


Propagation.NEVER:必须一起租房子,你有房子就分手。


最后一种是嵌套性事务 Propagation.NESTED,它属于懂事型女友,如果有房子了就以房子为基础做点小生意,卖个花生、水果啥的,如果买卖成了,那就继续发展;如果失败了,至少还有房子;如果没房子也没关系,一起赚钱买房子。

3.事务传播机制使用与演示

接下来我们演示一下事务传播机制的使用,以下面 3 个最典型的事务传播级别为例:

支持当前事务的 REQUIRED;
不支持当前事务的 REQUIRES_NEW;
嵌套事务 NESTED。
下来我们分别来看。

事务传播机制的示例,需要用到以下两张表:

4a8b9fbebc394be58f37b74da4f7eca3.png
创建一个 Spring Boot 项目,核心业务代码有 3 个:UserController、UserServcie 以及 LogService。在 UserController 里面调用 UserService 添加用户,并调用 LogService 添加日志。 

3.1 REQUIRED 使用演示

REQUIRED 支持当前事务。 UserController 实现代码如下,其中 save 方法开启了事务:

b965d8da3f7b465d896b4ad705a5539c.png
UserService 实现代码如下: 

3ba188f458184f03967fe5cb3301db7c.png
LogService 实现代码如下: 

563496fabacb45ce8bd8e45583857f05.png
执行结果:程序报错,两张表中都没有插入任何数据。 

执行流程描述:

首先 UserService 中的添加用户方法正常执行完成。
LogService 保存日志程序报错,因为使用的是 UserController 中的全局事务,所以整个事务回滚,步骤 1 中的操作也跟着回滚。


所以数据库中没有添加任何数据。

3.2 REQUIRED_NEW 使用演示

REQUIRED_NEW 不支持当前事务。 UserController 实现代码:

eb616d4c7963463580a0b0ad97a1d5b2.png
UserService 实现代码: 

252e9b742adb486bab8b6af348c88460.png
LogService 实现代码: 

1aef07803144444e8b4dbfab42c43f14.png
程序执行结果: 

User 表中成功添加了一条用户数据,Log 表执行失败,没有加入任何数据,但它并没有影响到 UserController 中的事务执行。


通过以上结果可以看出:LogService 中使用的是单独的事务,虽然 LogService 中的事务执行失败了,但并没有影响 UserController 和 UserService 中的事务。

3.3 NESTED 使用演示

NESTED 是嵌套事务。 UserController 实现代码如下:

fd77d79a20bc42ffafd66135f17dd2e4.png
UserService 实现代码如下: 

065f21f44fdc4e059738367ffaaaf919.png
LogService 实现代码如下: 

25e6b9ec0cc34b65b8f184b682b2446b.png
最终执行结果,用户表和日志表都没有添加任何数据。 

执行流程描述:

UserController 中调用了 UserService 的添加用户方法,UserService 使用 NESTED 循环嵌套事务,并成功执行了添加用户的方法。


UserService 中调用了 LogService 的添加方法,LogService 使用了 NESTED 循环嵌套事务,但在方法执行中出现的异常,因此回滚了当前事务。


因为 UserService 使用的是嵌套事务,所以发生回滚的事务是全局的,也就是说 UserService 中的添加用户方法也被回滚了,最终执行结果是用户表和日志表都没有添加任何数据。

总结

Spring 事务传播机制是包含多个事务的方法在相互调用时,事务是如何在这些方法间传播的。事务的传播级别有 7 个,支持当前事务的:REQUIRED、SUPPORTS、MANDATORY;不支持当前事务的:REQUIRES_NEW、NOT_SUPPORTED、NEVER,以及嵌套事务 NESTED,其中 REQUIRED 是默认的事务传播级别。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

蜀州凯哥

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值