Spring事务开发经验 回滚和不回滚?

关于Spring事务原理的知识可以看我的一篇文章:Spring事务原理 如何增强、回滚、提交。那么在明白事务原理之后,工作中使用Spring事务控制时候需要注意什么?我根据工作经验列出几个注意点:

  1. 开启事务需要经过代理对象调用
  2. 避免长事务,容易导致死锁和锁超时
  3. 嵌套事务间发生异常是回滚还是不回滚?

本文针对第3个问题配合源码和实验例子说明,什么情况下抛出异常事务回滚。Spring 事务中 catch 异常后会回滚吗?有2种说法:

  1. 如果事务中 catch 了异常并且不抛出,事务不会回滚。
  2. 如果事务中 catch 了异常,但是事务依然回滚。

以下实验均是基于 read commited隔离级别,SpringBoot 2.5.6版本。

单个service,单个事务方法内catch异常

实验结论:在catch完后不再重新抛出情况下,事务不受影响,成功提交

双 service 配合,双方法同事务,catch异常

在抛出异常的方法体外catch,让Spring框架感知到异常

A函数 UserService,开启一个事务

B函数 ComodityService,融入当前事务中

实验结论:整体事务失败回滚,出现 Transaction silently rolled back because it has been marked as rollback-only

在抛出异常的方法体内catch异常,让Spring框架感知不到异常

实验结论:整体事务执行成功,包括insertTest() insertB(),2条数据都插入成功。

双 Service 双函数、双事务,catch异常

这个实验和上面实验最核心区别是开启了双事务,一个大事务和一个小事务,两个事务是独立的

A函数,UserService插入user。B函数插入goods,CommodityService 开启新事务,此时是通过代理类调用的所以新事务生效。

insertGoods方法开启新事务,虽然也是在方法内抛出异常让Spring框架感知到了,但是并不影响外层insertUser事务。 

实验结论:A函数事务执行成功,B函数的事务执行失败回滚。

怎么解释这个现象?看日志,B函数开启了一个新事务,挂起了A事务。

B事务执行失败回滚后,Spring恢复了挂起的A事务继续执行,最后成功提交。由此可以推理出,Transaction silently rolled back because it has been marked as rollback-only

只会出现在多个代理对象的同个事务内函数嵌套执行时的情况,当某个方法抛出异常,由于是在同个事务内就算你catch了异常,偷偷消化了。但是被Spring感知到了,根据原子性原则,由于同个事务所有操作必须一起成功或失败,所以Spring选择回滚整体事务!

如果是同个代理对象内的多个函数嵌套执行,虽然也在同个事务内但后续的调用链都是基于目标对象this方法内调用没有走代理,所以异常是不会被Spring感知到的(除非第一个开启事务的函数抛出异常被Spring感知到),所以事务不会回滚。

 

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值