当前位置: 首页 > news >正文

解密Spring事务生效的内部机制

声明式事务和编程式事务对比:

  1. 声明式事务:
    • 使用注解或XML配置的方式,在代码中声明事务的属性和行为。
    • 通过AOP和代理模式实现,将事务管理与业务逻辑代码解耦。
    • 适用于大多数情况,简化了代码,提高了可维护性和可读性。
    • 常用的注解是@Transactional,可以应用在方法或类级别。
  2. 编程式事务:
    • 在代码中显式编写事务管理的代码逻辑。
    • 需要手动控制事务的开启、提交和回滚等操作。
    • 适用于需要更细粒度控制事务的情况,或者在声明式事务不适用的情况下使用。
    • 可以使用编程式事务的API,如Spring的TransactionTemplate或JDBC的事务API。

Spring 事务的本质其实就是数据库对事务的支持,没有数据库的事务支持,Spring 是无法提供事务功能的。对于纯 JDBC 操作数据库,想要用到事务,可以按照以下步骤进行(编程式事务同理)

1、获取连接 Connection con = DriverManager.getConnection()2、开启事务 con.setAutoCommit(true/false);3、执行 CRUD4、提交事务/回滚事务 con.commit() / con.rollback();5、关闭连接 conn.close();

在这里插入图片描述

当使用Spring的声明式事务后,我们可以只要写CRUD即可,其他由Spirng 自动完成。

本文主要讲解声明式事务

生效原理

下面是一个简单的示例,用于说明 Spring 事务的生效原理:

@Service
public class MyService {@Transactionalpublic void transferMoney(Account sourceAccount, Account targetAccount, double amount) {//省略逻辑处理}
}

声明式事务就是使用我们常见的@Transactional注解完成的,声明式事务优点就在于让事务代码与业务代码解耦,通过Spring中提供的声明式事务使用,我们也可以发觉我们只需要编写业务代码即可,而事务的管理基本不需要我们操心,Spring就像使用了魔法一样,帮我们自动完成了。

之所以那么神奇,本质还是依靠Spring框架提供的Bean生命周期相关回调接口和AOP结合完成的,简述如下:

这里思考下:如何保证同个线程请求时数据库多个操作使用的是同个Connection?

  • 通过自动代理创建器依次尝试为每个放入容器中的bean尝试进行代理
  • 尝试进行代理的过程对于事务管理来说,就是利用事务管理涉及到的增强器advisor,即TransactionAttributeSourceAdvisor
  • 判断当前增强器是否能够应用与当前bean上,怎么判断呢? —> advisor内部的pointCut喽 !
  • 如果能够应用,那么好,为当前bean创建代理对象返回,并且往代理对象内部添加一个TransactionInterceptor拦截器。
  • 此时我们再从容器中获取,拿到的就是代理对象了,当我们调用代理对象的方法时,首先要经过代理对象内部拦截器链的处理,处理完后,最终才会调用被代理对象的方法。(这里其实就是责任链模式的应用)
  • 当TransactionInterceptor的invoke()方法被执行时,它会先开启一个事务,然后再调用目标方法。如果目标方法执行成功,那么就会提交事务,否则就会回滚事务。
  • 在整个事务过程中,Spring会保证操作数据库时使用的是同一个连接。它是通过将一个数据库连接与一个ThreadLocal对象绑定起来,然后在需要操作数据库时通过该ThreadLocal对象来获取连接的。这样就可以避免多个连接导致的数据不一致问题。
    在这里插入图片描述

这里说下SpringBoot底层实现有一个AutoProxyRegistrar,简单来说,AutoProxyRegistrar顾名思义就是开启了AOP代理 ProxyTransactionManagementConfiguration是一个配置类,它又定义了另外三个bean:

  1. BeanFactoryTransactionAttributeSourceAdvisor:一个Advisor就是一个切面
  2. AnnotationTransactionAttributeSource:相当于Pointcut
  3. TransactionInterceptor:相当于中的 Advice,事务的拦截方法

AnnotationTransactionAttributeSource就是用来判断某个类上是否存在@Transactional注解, 或者判断某个方法上是否存在@Transactional注解的。

TransactionInterceptor就是代理逻辑,当某个类中存在@Transactional注解时,到时就产生一个 代理对象作为Bean,代理对象在执行某个方法时,最终就会进入到TransactionInterceptor的 invoke()方法。

对于被事务增强器TransactionAttributeSourceAdvisor代理的bean而言,代理对象内部会存在一个TransactionInterceptor,该拦截器内部构造了一个事务执行的模板流程:

protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass,final InvocationCallback invocation) throws Throwable {//TransactionAttributeSource内部保存着当前类某个方法对应的TransactionAttribute---事务属性源//可以看做是一个存放TransactionAttribute与method方法映射的池子TransactionAttributeSource tas = getTransactionAttributeSource();//获取当前事务方法对应的TransactionAttributefinal TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null);//定位TransactionManagerfinal TransactionManager tm = determineTransactionManager(txAttr);.....//类型转换为局部事务管理器PlatformTransactionManager ptm = asPlatformTransactionManager(tm);final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);if (txAttr == null || !(ptm instanceof CallbackPreferringPlatformTransactionManager)) {//TransactionManager根据TransactionAttribute创建事务后返回//TransactionInfo封装了当前事务的信息--包括TransactionStatusTransactionInfo txInfo = createTransactionIfNecessary(ptm, txAttr, joinpointIdentification);Object retVal;try {//继续执行过滤器链---过滤链最终会调用目标方法//因此可以理解为这里是调用目标方法retVal = invocation.proceedWithInvocation();}catch (Throwable ex) {//目标方法抛出异常则进行判断是否需要回滚completeTransactionAfterThrowing(txInfo, ex);throw ex;}finally {//清除当前事务信息cleanupTransactionInfo(txInfo);}...//正常返回,那么就正常提交事务呗(当然还是需要判断TransactionStatus状态先)commitTransactionAfterReturning(txInfo);return retVal;}...

事务拦截器(TransactionInterceptor)的处理过程总结如下:

  1. 方法调用前的处理:事务拦截器在目标方法调用前执行一些预处理操作。这包括检查当前是否存在事务上下文(TransactionContext),如果不存在则创建新的事务上下文。事务上下文包含了事务的相关信息,如事务的传播行为、隔离级别、超时设置等。事务拦截器还会根据事务定义的属性决定是否开启新的事务或者加入已有的事务。

  2. 方法调用:事务拦截器将目标方法调用传递给实际的目标对象,并执行目标方法。

  3. 方法调用后的处理:在目标方法执行完成后,事务拦截器会根据方法的执行结果决定是提交事务还是回滚事务。如果方法执行过程中发生了异常,事务拦截器会触发事务回滚,将事务恢复到调用该方法之前的状态。如果方法执行成功,事务拦截器会触发事务提交,将事务的操作永久保存到数据库。

事务拦截器通过使用事务管理器(TransactionManager) 来协调和控制事务的开始、提交和回滚操作。事务管理器负责和底层的数据访问框架(如JDBC、Hibernate)进行交互,确保事务的一致性和隔离性。

事务拦截器是通过配置切面(Aspect)和切入点(Pointcut) 的方式与目标方法进行关联。切面定义了在何时何地应用事务拦截器,而切入点则定义了哪些方法会被事务拦截器拦截。通过配置切面和切入点,可以灵活地控制事务的应用范围。

相关文章:

解密Spring事务生效的内部机制

声明式事务和编程式事务对比&#xff1a; 声明式事务&#xff1a; 使用注解或XML配置的方式&#xff0c;在代码中声明事务的属性和行为。通过AOP和代理模式实现&#xff0c;将事务管理与业务逻辑代码解耦。适用于大多数情况&#xff0c;简化了代码&#xff0c;提高了可维护性和…...

大数据时代下的数据安全防护

随着大数据时代的来临&#xff0c;数据安全防护成为了一个重要的问题。在大数据时代&#xff0c;数据的规模和价值都得到了极大的提升&#xff0c;因此数据安全的重要性也变得越来越突出。本文将从数据加密、访问控制、网络安全和人员管理四个方面来介绍大数据时代下的数据安全…...

RabbitMQ-常用命令

RabbitMQ常用命令 3.1 启动停止rabbitMQ命令 # 前台启动Erlang VM 和 RabbitMQ 当窗口关闭或者ctrlc时&#xff0c;使退出了。 rabbitmq-server# 使用系统命令启动 systemctl start rabbitmq-server# 后台启动 rabbitmq-server -detached# 停止rabbitMQ和Erlang VM rabbitmq-…...

Spring中依赖注入的继承bean的细节问题

介绍 有时我们会对一种类型的bean进行继承&#xff0c;在Spring生成bean的时候&#xff0c;返回类型有时是子类类型&#xff0c;有时会父类类型。那么到底在什么情况下用哪种类型呢&#xff1f;肯定有不少人会忽略这点&#xff0c;本篇文章就是把这个细节讲清楚 案例 父类Ba…...

海外腾讯云服务器手机上无法访问外网怎么办??

本文将介绍腾讯云服务器无法访问外网的一些常见原因以及解决办法&#xff0c;同时解答了手机无法访问腾讯云服务器的问题。 腾讯云服务器&#xff08;Tencent Cloud Server&#xff09;是一种基于云计算技术的虚拟服务器&#xff0c;可以满足用户对于计算、存储、网络等方面的需…...

python3+requests:接口自动化测试(二)

前言&#xff1a;上篇文章python3requestsunittest&#xff1a;接口自动化测试&#xff08;一&#xff09;&#xff1a;已经介绍了基于unittest框架的实现接口自动化&#xff0c;但是也存在一些问题&#xff0c;比如最明显的测试数据和业务没有区分开&#xff0c;接口用例不便于…...

uni-app:允许字符间能自动换行(英文字符、数字等)

<template><view class"container"><!-- 这里是你的文本内容 -->{{ multilineText }}</view> </template><style> .container {word-break: break-all; } </style>例如&#xff1a; <template><view class"…...

day 42 |● 121. 买卖股票的最佳时机 ● 122.买卖股票的最佳时机II

121. 买卖股票的最佳时机 dp数组需要记录两种状态&#xff0c;一种是当天时手中还持有股票&#xff0c;一种是当天时手中已卖出股票。 func maxProfit(prices []int) int {dp : make([][]int, len(prices))dp[0] []int{-prices[0], 0}for i : 1; i < len(prices); i{val0…...

SQLserver基础入门理论(超基础)

♥️作者&#xff1a;小刘在C站 ♥️个人主页&#xff1a; 小刘主页 ♥️努力不一定有回报&#xff0c;但一定会有收获加油&#xff01;一起努力&#xff0c;共赴美好人生&#xff01; ♥️学习两年总结出的运维经验&#xff0c;以及思科模拟器全套网络实验教程。专栏&#xf…...

(三)行为模式:7、观察者模式(Observer Pattern)(C++示例)

目录 1、观察者模式&#xff08;Observer Pattern&#xff09;含义 2、观察者模式的UML图学习 3、观察者模式的应用场景 4、观察者模式的优缺点 &#xff08;1&#xff09;优点&#xff1a; &#xff08;2&#xff09;缺点 5、C实现观察者模式的实例 1、观察者模式&…...

2019CVPR Semantic Graph Convolutional Networks for 3D Human Pose Regression

基于语义图卷积网络的三维人体姿态回归 源码 https://github.com/garyzhao/SemGCN 摘要 在本文中&#xff0c;我们研究了学习图卷积网络&#xff08;GCN&#xff09;回归的问题。GCN的当前体系结构受限于卷积滤波器和共享的变换矩阵为的小感受野。为了解决这些限制&#xff…...

大数据课程K16——Spark的梯度下降法

文章作者邮箱&#xff1a;yugongshiyesina.cn 地址&#xff1a;广东惠州 ▲ 本章节目的 ⚪ 了解Spark的梯度下降法&#xff1b; ⚪ 了解Spark的梯度下降法家族&#xff08;BGD&#xff0c;SGD&#xff0c;MBGD&#xff09;&#xff1b; ⚪ 掌握Spark的MLlib实现…...

springboot:时间格式化的5种方法(解决后端传给前端的时间格式转换问题)推荐使用第4和第5种!

本文转载自&#xff1a;springboot&#xff1a;时间格式化的5种方法&#xff08;解决后端传给前端的时间显示不一致&#xff09;_为什么前端格式化日期了后端还要格式化_洛泞的博客-CSDN博客 时间问题演示 为了方便演示&#xff0c;我写了一个简单 Spring Boot 项目&#xff…...

六、vim编辑器的使用

1、编辑器 (1)编辑器就是一款软件。 (2)作用就是用来编辑文件&#xff0c;譬如编辑文字、编写代码。 (3)Windows中常用的编辑器&#xff0c;有自带的有记事本(notepad)&#xff0c;比较好用的notepad、VSCode等。 (4)Linux中常用的编辑器&#xff0c;自带的最古老的vi&…...

【易售小程序项目】项目介绍与系列文章集合

项目介绍 易售二手小程序主要用于校园中二手商品的交易&#xff0c;该系列文章会记录这个小程序前端的整个开发过程并提供详细代码&#xff0c;后台主要基于若依管理系统搭建&#xff0c;文章中也会提及后端关键部分的实现及代码。希望该系列文章可以帮助小白了解项目的开发流…...

游戏服务器成DDoS最大攻击重灾区

游戏产业的迅猛发展也让游戏产业成为被黑客攻击的重灾区。什么原因让游戏行业成为DDoS的攻击重点。总结有如下原因和主要手段&#xff1a; 1.游戏行业的攻击成本较低&#xff0c;攻防成本1&#xff1a;N。随着DDoS攻击的打法越来越复杂&#xff0c;攻击点更是越来越多&#xff…...

[SpringBoot3]博客管理系统(源码放评论区了)

八、博客管理系统 创建新的SpringBoot项目&#xff0c;综合运用以上知识点&#xff0c;做一个文章管理的后台应用。依赖&#xff1a; Spring WebLombokThymeleafMyBatis FrameworkMySQL DriverBean Validationhutool 需求&#xff1a;文章管理工作&#xff0c;发布新文章&…...

C语言——指针基本语法

概述 内存地址 在计算机内存中&#xff0c;每个存储单元都有一个唯一的地址(内存编号)。 通俗理解&#xff0c;内存就是房间&#xff0c;地址就是门牌号 指针和指针变量 指针&#xff08;Pointer&#xff09;是一种特殊的变量类型&#xff0c;它用于存储内存地址。 指针的实…...

elementui table 在浏览器分辨率变化的时候界面异常

异常点&#xff1a; 界面显示不完整&#xff0c;表格卡顿&#xff0c;界面已经刷新完成&#xff0c;但是表格的宽度还在一点一点变化&#xff0c;甚至有无线延伸的情况 思路&#xff1a; 1. 使用doLayout 这里官方文档有说明&#xff0c; 所以我的想法是&#xff0c;监听浏览…...

六、Kafka-Eagle监控

目录 6.1 MySQL 环境准备6.2 Kafka 环境准备6.3 Kafka-Eagle 安装 6.1 MySQL 环境准备 Kafka-Eagle 的安装依赖于 MySQL&#xff0c;MySQL 主要用来存储可视化展示的数据 6.2 Kafka 环境准备 修改/opt/module/kafka/bin/kafka-server-start.sh 命令 vim bin/kafka-server-sta…...

SpringBoot-17-MyBatis动态SQL标签之常用标签

文章目录 1 代码1.1 实体User.java1.2 接口UserMapper.java1.3 映射UserMapper.xml1.3.1 标签if1.3.2 标签if和where1.3.3 标签choose和when和otherwise1.4 UserController.java2 常用动态SQL标签2.1 标签set2.1.1 UserMapper.java2.1.2 UserMapper.xml2.1.3 UserController.ja…...

[特殊字符] 智能合约中的数据是如何在区块链中保持一致的?

&#x1f9e0; 智能合约中的数据是如何在区块链中保持一致的&#xff1f; 为什么所有区块链节点都能得出相同结果&#xff1f;合约调用这么复杂&#xff0c;状态真能保持一致吗&#xff1f;本篇带你从底层视角理解“状态一致性”的真相。 一、智能合约的数据存储在哪里&#xf…...

vscode里如何用git

打开vs终端执行如下&#xff1a; 1 初始化 Git 仓库&#xff08;如果尚未初始化&#xff09; git init 2 添加文件到 Git 仓库 git add . 3 使用 git commit 命令来提交你的更改。确保在提交时加上一个有用的消息。 git commit -m "备注信息" 4 …...

基于距离变化能量开销动态调整的WSN低功耗拓扑控制开销算法matlab仿真

目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.算法仿真参数 5.算法理论概述 6.参考文献 7.完整程序 1.程序功能描述 通过动态调整节点通信的能量开销&#xff0c;平衡网络负载&#xff0c;延长WSN生命周期。具体通过建立基于距离的能量消耗模型&am…...

《Playwright:微软的自动化测试工具详解》

Playwright 简介:声明内容来自网络&#xff0c;将内容拼接整理出来的文档 Playwright 是微软开发的自动化测试工具&#xff0c;支持 Chrome、Firefox、Safari 等主流浏览器&#xff0c;提供多语言 API&#xff08;Python、JavaScript、Java、.NET&#xff09;。它的特点包括&a…...

12.找到字符串中所有字母异位词

&#x1f9e0; 题目解析 题目描述&#xff1a; 给定两个字符串 s 和 p&#xff0c;找出 s 中所有 p 的字母异位词的起始索引。 返回的答案以数组形式表示。 字母异位词定义&#xff1a; 若两个字符串包含的字符种类和出现次数完全相同&#xff0c;顺序无所谓&#xff0c;则互为…...

【OSG学习笔记】Day 16: 骨骼动画与蒙皮(osgAnimation)

骨骼动画基础 骨骼动画是 3D 计算机图形中常用的技术&#xff0c;它通过以下两个主要组件实现角色动画。 骨骼系统 (Skeleton)&#xff1a;由层级结构的骨头组成&#xff0c;类似于人体骨骼蒙皮 (Mesh Skinning)&#xff1a;将模型网格顶点绑定到骨骼上&#xff0c;使骨骼移动…...

网络编程(UDP编程)

思维导图 UDP基础编程&#xff08;单播&#xff09; 1.流程图 服务器&#xff1a;短信的接收方 创建套接字 (socket)-----------------------------------------》有手机指定网络信息-----------------------------------------------》有号码绑定套接字 (bind)--------------…...

MySQL JOIN 表过多的优化思路

当 MySQL 查询涉及大量表 JOIN 时&#xff0c;性能会显著下降。以下是优化思路和简易实现方法&#xff1a; 一、核心优化思路 减少 JOIN 数量 数据冗余&#xff1a;添加必要的冗余字段&#xff08;如订单表直接存储用户名&#xff09;合并表&#xff1a;将频繁关联的小表合并成…...

C# 表达式和运算符(求值顺序)

求值顺序 表达式可以由许多嵌套的子表达式构成。子表达式的求值顺序可以使表达式的最终值发生 变化。 例如&#xff0c;已知表达式3*52&#xff0c;依照子表达式的求值顺序&#xff0c;有两种可能的结果&#xff0c;如图9-3所示。 如果乘法先执行&#xff0c;结果是17。如果5…...