当前位置:网站首页>把@Transactional事务注解用到如此炉火纯青,真的强!
把@Transactional事务注解用到如此炉火纯青,真的强!
2022-07-30 01:15:00 【石杉的架构笔记】
文章来源:https://c1n.cn/n7H3w
目录
背景
Spring 事务的传播行为
Spring 事务的回滚机制
@Transactional 注解底层实现
总结
背景
前两天在工作中忙的焦头烂额,涉及到 @Transactional 对于事务的控制,便仔细研究了一下,颇有所获,花费好了几天测试整理,今天才发表出来,希望老铁们能有所获吧。
Spring 事务的传播行为
话不多说直奔正题。先简单介绍一下 Spring 事务的传播行为。
所谓事务的传播行为是指,如果在开始当前事务之前,一个事务上下文已经存在,此时有若干选项可以指定一个事务性方法的执行行为。
在 TransactionDefinition 定义中包括了如下几个表示传播行为的常量:
TransactionDefinition.PROPAGATION_REQUIRED:如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。这是默认值。
TransactionDefinition.PROPAGATION_REQUIRES_NEW:创建一个新的事务,如果当前存在事务,则把当前事务挂起。
TransactionDefinition.PROPAGATION_SUPPORTS:如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。
TransactionDefinition.PROPAGATION_NOT_SUPPORTED:以非事务方式运行,如果当前存在事务,则把当前事务挂起。
TransactionDefinition.PROPAGATION_NEVER:以非事务方式运行,如果当前存在事务,则抛出异常。
TransactionDefinition.PROPAGATION_MANDATORY:如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。
TransactionDefinition.PROPAGATION_NESTED:如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;如果当前没有事务,则该取值等价于TransactionDefinition.PROPAGATION_REQUIRED。
Spring事务的回滚机制
然后说一下Spring事务的回滚机制:Spring 的 AOP 即声明式事务管理默认是针对 unchecked exception 回滚。
Spring 的事务边界是在调用业务方法之前开始的,业务方法执行完毕之后来执行 commit or rollback(Spring 默认取决于是否抛出 runtimeException)。
如果你在方法中有 try{}catch(Exception e){} 处理,那么 try 里面的代码块就脱离了事务的管理,若要事务生效需要在 catch 中 throw new RuntimeException ("xxxxxx"); 这一点也是面试中会问到的事务失效的场景。
@Transactional 注解底层实现
再简单介绍一下 @Transactional 注解底层实现方式吧,毫无疑问,是通过动态代理,那么动态代理又分为 JDK 自身和 CGLIB,这个也不多赘述了,毕竟今天的主题是如何将 @Transactional 对于事物的控制应用到炉火纯青。哈哈~
第一点要注意的就是在 @Transactional 注解的方法中,再调用本类中的其他方法 method2 时,那么 method2 方法上的 @Transactional 注解是不!会!生!效!的!
但是加上也并不会报错,拿图片简单帮助理解一下吧。这一点也是面试中会问到的事务失效的场景。

通过代理对象在目标对象前后进行方法增强,也就是事务的开启提交和回滚。那么继续调用本类中其他方法是怎样呢?
如下图:

可见目标对象内部的自我调用,也就是通过 this. 指向的目标对象将不会执行方法的增强。
先说第二点需要注意的地方,等下说如何解决上面第一点的问题。第二点就是 @Transactional 注解的方法必须是公共方法,就是必须是 public 修饰符!!!
至于这个的原因,发表下个人的理解吧,因为 JVM 的动态代理是基于接口实现的,通过代理类将目标方法进行增强。
想一下也是啦,没有权限访问那么你让我怎么进行?好吧,这个我也没有深入研究底层,个人理解个人理解。
在这里我也放个问题吧,希望有高手可以回复指点指点我,因为 JVM 动态代理是基于接口实现的,那么是不是 service 层都要按照接口和实现类的开发模式,注解才会生效呢。
就是说 controller 层直接调用没有接口的 service 层,加了注解也一样不起作用吧,这个懒了,没有测试,其一是因为没有人会这么开发吧,其二是我就认为是不起作用的,哈哈。
下面来解决一下第一点的问题,如何在方法中调用本类中其他方法呢。
通过 AopContext.currentProxy () 获取到本类的代理对象,再去调用就好啦。
因为这个是 CGLIB 实现,所以要开启 AOP,当然也很简单,在 springboot 启动类上加上注解 @EnableAspectJAutoProxy(exposeProxy = true) 就可以啦,这个依赖大家自行搜一下就好啦。
要注意,注意,代理对象调用的方法也要是 public 修饰符,否则方法中获取不到注入的 bean,会报空指针错误。
emmmm,我先把调用的方式和结果说下吧。自己简单写了代码,有点粗糙,就不要介意啦,嘿嘿!
Controller 中调用 Service:
@RestController
public class TransactionalController {
@Autowired
private TransactionalService transactionalService;
@PostMapping("transactionalTest")
public void transacionalTest(){
transactionalService.transactionalMethod();
}
}Service 中实现对事务的控制:接口
public interface TransactionalService {
void transactionalMethod();
}Service 中实现对事务的控制:实现类(各种情况的说明都写在图片里了,这样方便阅读,有助于快速理解吧)


上面两种情况不管使不使用代理调用方法 1 和方法 2,方法 transactionalMethod 都处在一个事务中,四条更新操作全部失败。
那么有人可能会有疑问了,在方法 1 和方法 2 上都加 @Transactional 注解呢?答案是结果和上面是一致的。
小结:只要方法 transactionalMethod 上有注解,并且方法 1 和方法 2 都处于当前事务中(不使用代理调用,方法 1 和方法 2 上的 @Transactional 注解是不生效的;使用代理,需要方法 1 和方法 2 都处在 transactionalMethod 方法的事务中,默认或者嵌套事务均可,当然也可以不加 @Transactional 注解),那么整体保持事务一致性。
如果想要方法 1 和方法 2 均单独保持事务一致性怎么办呢,刚说过了,如果不是用代理调用 @Transactional 注解是不生效的,所以一定要使用代理调用实现,然后让方法 1 和方法 2 分别单独开启新的事务,便 OK 啦。
下面摆上图片:


这两种情况都是方法 1 和方法 2 均处在单独的事务中,各自保持事务的一致性。
接下来进行进一步的优化,可以在 transactionalMethod 方法中分别对方法 1 和方法 2 进行控制。
要将代码的艺术发挥到极致嘛,下面装逼开始。

代码太长了,超过屏幕了,粘贴出来截的图,红框注释需要仔细看,希望不要影响你的阅读体验,至此,本篇关于 @Transactioinal 注解的使用就到此为止啦,
总结
简单总结一下吧:
就是 @Transactional 注解保证的是每个方法处在一个事务,如果有 try 一定在 catch 中抛出运行时异常。
方法必须是 public 修饰符。否则注解不会生效,但是加了注解也没啥毛病,不会报错,只是没卵用而已。
this. 本方法的调用,被调用方法上注解是不生效的,因为无法再次进行切面增强。
------------- END -------------
扫码免费获取600+页石杉老师原创精品文章汇总PDF
原创技术文章汇总
点个在看你最好看边栏推荐
- 畅玩西安全攻略
- 排序相关应用
- How to set up hybrid login in SQL server in AWS
- How Filebeat ensures that the log file is still correctly read when the log file is split (or rolled)
- Replace the executable file glibc version of the one
- msyql set names 字符转换处理
- 【Vmware NSX-V基本架构及组件安装】
- Recommendation system: collection of user "behavioral data" [use Kafka and Cassandra to process data] [if it overlaps with business data, it also needs to be collected independently]
- 重新定义分析 - EventBridge 实时事件分析平台发布
- 转发和重定向的区别及使用场景
猜你喜欢

【Vmware NSX-V基本架构及组件安装】

Minimum number to rotate array
![[Flutter] Detailed explanation of the use of the Flutter inspector tool, viewing the Flutter layout, widget tree, debugging interface, etc.](/img/29/a6ec7e00df289f68dcd39fe4f35fd3.png)
[Flutter] Detailed explanation of the use of the Flutter inspector tool, viewing the Flutter layout, widget tree, debugging interface, etc.

Validation Framework-01

自学HarmonyOS应用开发(49)- 引入地图功能

推荐系统:用户“行为数据”的采集【使用Kafaka、Cassandra处理数据】【如果与业务数据重合,也需要独自采集】

转发和重定向的区别及使用场景

推荐系统:特征工程、常用特征

CMake Tutorial 巡礼(1)_基础的起点
[email protected](using passwordYES)"/>Navicat error: 1045-Access denied for user [email protected](using passwordYES)
随机推荐
Recurrent Neural Network (RNN)
Recommendation system: collection of user "behavioral data" [use Kafka and Cassandra to process data] [if it overlaps with business data, it also needs to be collected independently]
数据流图、数据字典
重建二叉树
CMake Tutorial Tour(0)_Overview
Docker installs redis cluster (including deployment script)
SSM integration case
vmtouch——Linux下的文件缓存管理神器
【MySQL总结】
自学HarmonyOS应用开发(53)- 获取当前位置
Nacos micro service ~ Nacos 】 【 configuration of the center
LABVIEW详细介绍:LABVIEW是什么软件?都可以干什么?
Print linked list from end to beginning
二维数组的查找
Google Chrome (google) is set to translate Chinese, the translation option does not take effect or the translation option does not pop up
高德地图jsapi不生效 INVALID_USER_SCODE
Minimum number to rotate array
泰克Tektronix示波器软件TDS2012|TDS2014|TDS2022上位机软件NS-Scope
谷歌浏览器(google)设置翻译中文,翻译选项不生效或没有弹出翻译选项
【Flutter】Flutter inspector 工具使用详解,查看Flutter布局,widget树,调试界面等