【Spring】-编程式事务和声明式事务

spring中控制事务的方式有两种:编程式事务和声明式事务,今天我以两种事务出发,对spring中实现事务的@EnableTransactionManagement和@Transaction两个注解的底层原理进行讨论。

一、编程式事务

什么是编程式事务?

硬编码的方式实现事务,在代码中手动开始、提交和回滚事务

编程式事务实现思想是什么?

  • 配置PlatformTransactionManager事务管理器去控制事务
  • 配置TransactionDefinition设置事务属性
  • 配置TransactionTemplate控制事务

步骤和原理

1、定义数据源

2、定义一个PlatformTransactionManager 事务管理器,指定数据源。控制事务的操作(开始、提交、回滚)

3、定义TransactionDefinition 事务属性,可以配置事务属性信息

4、开启事务操作。通过调用getTransaction方法

补充:ThreadLocal中存储了datasource和connection的映射

这样当我们开启事务的时候会创建一个数据库连接,通过ThreadLocal保证线程的同步

5、执行业务操作

6、commit提交/rollback回滚事务

优缺点

优点:

以在代码中精确地控制事务的起始点、提交点和回滚点,实现更细粒度的事务管理。

缺点:

  1. 代码侵入性:编程式事务管理会将事务管理逻辑直接嵌入到业务代码中,增加了代码的复杂度和维护成本,使得业务逻辑与事务管理耦合在一起。
  2. 重复性工作:在多个业务方法中可能需要重复编写事务管理逻辑,增加了代码冗余和维护工作量。

二、声明式事务

什么是声明式事务?

通过配置的方式去管理事务,可以是xml配置文件,也可以使用spring提供的@Transactional注解

声明式事务实现思想是什么?

  • 添加@EnableTransactionManagement注解
  • 添加@Transactional注解

步骤和原理

1、启用事务管理功能-配置类上加上@EnableTransactionManagement注解

2、定义事务管理器

3、需要开启事务的目标接口/类/方法上添加@Transaction注解

4、执行业务逻辑

5、启动spring容器,获取bean执行业务逻辑

优缺点

优点:

  1. 与业务逻辑分离:声明式事务管理将事务管理逻辑从业务代码中分离出来,使得业务逻辑更清晰,降低了代码的耦合性。
  2. 配置简单:通过注解或XML配置,可以简单地定义事务的传播行为、隔离级别等属性,而无需在每个业务方法中编写重复的事务管理代码。
  3. 易于维护:由于事务管理逻辑集中在配置中,易于维护和修改,提高了代码的可读性和可维护性。
  4. 提高一致性:声明式事务管理可以确保在所有业务方法中都应用相同的事务管理策略,提高了事务管理的一致性。

缺点:

  1. 灵活性有限:声明式事务管理的灵活性相对较低,无法在运行时动态地改变事务管理策略,有一定的局限性。
  2. RPC远程调用成功,但是本地事务回滚了,RPC调用无法回滚。并且事务中有远程调用,会拉长整个事务,导致本地事务的数据库连接一致被占用,最后可能会导致数据库连接池耗尽

在阿里巴巴的开发手册中也明确标出,我们用@Transactional注解的时候要谨慎,大家在业务场景中要谨慎使用哦!


上面我已经对spring实现事务的两种方式分别进行了说明,下面我们看看它的源码,解开事务这个神秘面纱!

三、源码分析

@EnableTransactionManagement

作用是什么?

开启spring自动管理事务。在spring容器启动的时候,会拦截所有bean的创建,判断当前bean中有没有用@Transaction注解,是不是需要让spring管理事务

判断规则:

  • public方法上有没有用@Transaction注解
  • 和bean的类相关的类/接口上有没有用@Transaction注解

当满足规则之后会通过aop的方式创建代理,并且在代理中添加一个TransactionInterceptor拦截器

注意:@Transaction注解在代理对象被创建并且方法被调用时生效

@Transactional注解生效,必须确保Spring能够为目标类创建代理对象,并且方法通过代理对象调用

TransactionInterceptor拦截器的作用是什么?

拦截@Transaction方法,在方法前后添加事务额外逻辑

如果代理中还有其他拦截器,拦截器的顺序如何指定呢?

通过order()方法修改事务拦截器的执行顺序

注意:默认值是 LOWEST_PRECEDENCE = Integer.MAX_VALUE,拦截器的执行顺序是order升序

 int order() default Ordered.LOWEST_PRECEDENCE;

@Import(TransactionManagementConfigurationSelector.class)在这里的作用是什么?

@Import的作用是批量导入需要注册的类,完成bean的注册

那@Import导入了哪些类?

通过点进去TransactionManagementConfigurationSelector我们发现,里面有一个selectImports方法,这个方法的返回值是一个字符串数组,返回的字符串数组如果是正常的全限定类名才会被容器识别

通过查看selectImports方法源码,我们发现return了两个类-AutoProxyRegistrar、ProxyTransactionManageMentConfiguration,也就是说Import导入了这两个类

  1. AutoProxyRegistrar:启用spring aop功能,创建代理
  2. ProxyTransactionManageMentConfiguration:在aop中添加事务拦截器

①、AutoProxyRegistrar

点进源码,我们看registerBeanDefinitions这个方法,看过spring容器启动流程的小伙伴会发现,其中流程就会调用这个方法,AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry)作用是向spring容器注册一个自动代理创建器,从而启用AOP代理的功能

在方法内部会导入InfrastructureAdvisorAutoProxyCreator类,给spring 容器中注册了一个后置处理器-BeanPostProcessor,拦截所有bean的创建并将符合规则的bean创建代理,对类进行增强

在生命周期阶段,创建bean的时候只有需要增强,就会调用BeanPostProcessor的after进行增强

②、ProxyTransactionManageMentConfiguration

配置类,一般是提供加了@Bean的一些方法。注册了一个事务拦截器TransactionInterceptor

总:通过对上面两个导入的类的源码分析我们明确了他们的作用,我们使用@Transaction标注的bean会通过AutoProxyRegistrar去启用aop功能,通过ProxyTransactionManagementConfiguration在aop中添加事务拦截器从而实现事务管理

如果有想要交流的内容欢迎在评论区进行留言,如果这篇文档受到了您的喜欢那就留下你点赞+收藏+评论脚印支持一下博主~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/824736.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Adobe将Sora、Runway、Pika,集成在PR中

4月15日晚,全球多媒体巨头Adobe在官网宣布,将OpenAI的Sora、Pika 、Runway等著名第三方文生视频模型,集成在视频剪辑软件Premiere Pro中(简称“PR”)。 同时,Adob也会将自身研发的Firefly系列模型包括视频…

【Python】高级进阶(专版提升3)

Python 1 程序结构1.1 模块 Module1.1.1 定义1.1.2 作用1.1.3 导入1.1.3.1 import1.1.3.2 from import 1.1.4 模块变量1.1.5 加载过程1.1.6 分类 1.2 包package1.2.1 定义1.2.2 作用1.2.3 导入1.1.3.1 import1.1.3.2 from import 2 异常处理Error2.1 异常2.2 处理 3 迭代3.1 可…

InfluxDB v1.8

数据存储模型 points(数据点)time(时间戳)measurement(测量指标)field(测量值 key-value)至少一个tag(标签 key-value)零或多个和MySQL对比 series是共享同一个retention policy,measurement以及tag set的数据集合 InfluxDBMySQLmeasurementtablepointscoltagrow(with index)…

Three.js 入门——核心概念和坐标系理解

Three.js 是什么? 一个封装了 WebGL 的库,简化 WebGL 的使用 WebGL vs OpenGL OpenGL 主要被认为是一种 API(应用程序编程接口),它为我们提供了大量可用于操作图形和图像的函数,主要用 C语言编写的。 然…

python辅助QQ登入

python辅助QQ登入 import pyautogui import time import random from pyautogui import ImageNotFoundException# 生成随机等待时间,范围在1到3秒之间 random_time random.uniform(1, 3)def find_and_click(image_path, moveFalse, execute_nextTrue):try:image_l…

【QT学习】7.事件,把文本显示在页面中(文本可变),鼠标指针切换,鼠标左键右键按下,qt设置背景样式

0.创建项目,事件的创建 1.事件的位置 2.这就是多态,子类重写父类函数,子类调用子类函数,也可以调用父类函数。但同函数名 1.要求:文本显示在页面中(文本可变) 1.文本显示在页面的核心代码 主要步…

vue3通过事件总线不同组件之间传递消息(两个组件可以没有任何关系)

首先在main.js中定义 const app createApp(App) app.config.globalProperties.$eventBus new mitt() // 创建全局事件总线对象然后在发送事件的组件中写&#xff08;js和ts导入方式不太一样&#xff0c;用法一样&#xff09; <script setup> import {getCurrentInsta…

DRF requets源码分析

【四】requets源码分析 【1】查看request传递的数据 &#xff08;1&#xff09;视图层 编写传输数据的接口查看request方法的参数 class BookAPIView(APIView):def get(self, request, *args, **kwargs):return Response({body: request.body, data: request.data, post: r…

【Web】DASCTF X GFCTF 2022十月挑战赛题解

目录 EasyPOP hade_waibo EasyLove BlogSystem EasyPOP 先读hint.php sorry.__destruct -> secret_code::secret() exp: $anew sorry(); $bnew secret_code(); $a->password"suibian"; $a->name"jay"; echo serialize($a); 真暗号啊&…

web项目中jsp页面不识别el表达式

如果使用el表达式出现下图问题 ** 解决办法 ** 这是因为maven创建项目时&#xff0c;web.xml头部声明默认是2.3&#xff0c;这个默认jsp关闭el表达式 修改web.xml文件开头的web-app的版本 <?xml version"1.0" encoding"UTF-8"?> <web-app x…

Vue3 Reactive和Ref

当你在使用Vue 3时&#xff0c;reactive 和 ref 是两个常用的响应式API。它们都是用来跟踪状态变化并在UI中进行响应式更新的。 1. ref ref 用于创建一个响应式的基本数据类型变量&#xff0c;例如数字、字符串等。它返回一个带有 .value 属性的对象&#xff0c;该属性包含了…

Python爬取猫眼电影票房 + 数据可视化

目录 主角查看与分析 爬取可视化分析猫眼电影上座率前10分析猫眼电影票房场均人次前10分析猫眼电影票票房占比分析 主角查看与分析 爬取 对猫眼电影票房进行爬取&#xff0c;首先我们打开猫眼 接着我们想要进行数据抓包&#xff0c;就要看网站的具体内容&#xff0c;通过按F12…

Postman之安装

Postman工具之介绍与安装 Postman是什么&#xff1f;Postman有几种安装方式&#xff1f; Postman是什么&#xff1f; postman是一款http客户端的模拟器&#xff0c;它可以模拟发出各种各样的网络请求&#xff0c;用于接口测试。 Postman有几种安装方式&#xff1f; 两种&…

4.17 网络编程

思维导图 select实现TCP并发服务器 #include <myhead.h> #define SER_IP "192.168.125.26" #define SER_PORT 8888int main(int argc, const char *argv[]) {int sfd socket(AF_INET,SOCK_STREAM,0);if(sfd -1){perror("socket error");return -1…

hvv准备ing

常见的SQL注入&#xff1f;sqlmap的常用命令和功能&#xff1f;SQLMAPAPI怎么使用&#xff1f;sqlmap --os-shell 原理&#xff1a;在数据交互中&#xff0c;前端的数据传入到后台处理 时&#xff0c;由于后端没有做严格的判断&#xff0c;导致其传入的“数 据”拼接到SQL语句…

c++程序员通用成长规划

一、长期计划 要有一个长期的学习计划&#xff0c;确定学习方向&#xff0c;拆分为各个模块&#xff0c;每天学习多少&#xff0c;根据实际情况灵活调整&#xff0c;一切以当前实际工作为主后续发展为辅&#xff0c;并且要坚持。这里的坚持不是强制的&#xff0c;比如今天有事…

Spring Boot深度解析:是什么、为何使用及其优势所在

在Java企业级应用开发的漫长历史中&#xff0c;Spring框架以其卓越的依赖注入和面向切面编程的能力&#xff0c;赢得了广大开发者的青睐。然而&#xff0c;随着技术的不断进步和项目的日益复杂&#xff0c;传统的Spring应用开发流程逐渐显得繁琐和低效。为了解决这一问题&#…

基于Java+SpringBoot+Mybaties-plus+Vue+elememt 小区物业管理系统 的设计与实现

一.项目介绍 系统分为管理员 和 业主 两块&#xff1a; 管理员点击进入到系统操作界面&#xff0c;可以对首页、业主信息管理、管理员信息管理、 楼栋和房屋信息管理、物业费管理、地下停车位管理、公告信息管理、报修信息管理、 投诉管理以及个人信息等功能模块 …

libftdi1学习笔记 5 - SPI Nor Flash

目录 1. 初始化 2. CS控制例子 3. 读ID 3.1 制造商 3.2 容量大小 3.3 设置IO类型 3.3.1 setQSPIWinbond 3.3.2 setQSPIMxic 3.3.3 setQSPIMicrochip 3.3.4 setQSPIMicron 4. 写保护 5. 等待空闲 6. 擦除扇区 7. 页编程 8. 页读 9. 写 10. 读 11. 验证 基于M…

cesium加载高层级离线影像地图瓦片(天地图、19级Arcgis)

实际加载效果如图&#xff1a; 1、下载离线地图瓦片方式&#xff08;多种任选其一&#xff0c;个人倾向于Qgis工具&#xff09;&#xff1a; 方式1、采用第三方下载工具如&#xff1a;91卫图、水经注、全能电子地图下载器、bigemap等等。&#xff08;这些有的下载层级不够&…