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

Seata客户端代理增强核心源码解析

文章目录

  • 前言
  • 一、SeataAutoDataSourceProxyCreator
    • 1.1、DataSourceProxy
    • 1.2、PreparedStatementProxy
  • 二、Seata代理增强
    • 2.1、executeAutoCommitFalse
      • 2.1.1、生成前置镜像
      • 2.1.2、生成后置镜像
      • 2.1.3、生成undolog
  • 总结


前言

  当调用到标注了@GlobalTransactional注解的方法,最终会执行到io.seata.tm.api.TransactionalTemplateexecute方法:
在这里插入图片描述
  这是一个标准的事务编程模型。rs = business.execute();是执行目标业务代码的逻辑,其中就包含了如何生成前置镜像、后置镜像、记录undolog、向TC注册分支事务的逻辑。


一、SeataAutoDataSourceProxyCreator

  在Seata与Spring boot整合过程中,会向容器中条件装配一个SeataAutoDataSourceProxyCreator类型的Bean。
在这里插入图片描述
  SeataAutoDataSourceProxyCreator继承自AbstractAutoProxyCreator
在这里插入图片描述
  重写了父类的wrapIfNecessary方法,在其中会对普通的数据源进行包装:
在这里插入图片描述
  根据模式的不同,进行包装,这里的模式是在配置文件中声明的:
在这里插入图片描述
  以AT模式为例,最终返回的是一个DataSourceProxy对象:
在这里插入图片描述
  上述过程是在Spring启动过程中完成的。

1.1、DataSourceProxy

  DataSourceProxy中有一个关键的方法getConnection(),它会返回一个代理后的proxy:
在这里插入图片描述
  ConnectionProxy又继承了AbstractConnectionProxy,其中有关键方法:createStatementprepareStatement
在这里插入图片描述
  prepareStatement是重写JDBC的方法。如果是在AT模式下:

  • 使用 SQLVisitor 工厂获取 SQL 语义识别器。目的是分析这条 SQL 是 INSERT、UPDATE、DELETE 还是其他类型。
  • 如果是 INSERT 语句且识别器只有一个,获取目标表的元信息(主键、列等),创建支持主键返回的 PreparedStatement。
  • 返回PreparedStatementProxy代理对象,以支持 Seata 的事务回滚、日志等机制。

  而createStatement,核心目的是为普通 Statement 加一层代理,以支持事务的拦截与管理。

1.2、PreparedStatementProxy

  当执行业务代码的sql时,会执行io.seata.rm.datasource.PreparedStatementProxyexecute方法:
在这里插入图片描述
  在这里会进行一系列的判断:
  如果当前没有启用全局锁,且当前分支事务不是 AT 模式,就直接使用原生的 JDBC Statement 执行逻辑,不走 Seata 的增强逻辑。
在这里插入图片描述
   如果 sqlRecognizers 为空,就重新解析 SQL,SQL Recognizer 是 Seata 内部的语法分析器,用于识别 SQL 的类型和结构(如表名、主键、字段等):
在这里插入图片描述
   判断 SQL 是否识别成功:如果不能识别 SQL 类型,就走默认执行器 PlainExecutor —— 它不做增强处理,直接执行 SQL。
在这里插入图片描述
   根据识别出的 SQL 类型选择增强执行器,并且执行上报分支事务,前置镜像,后置镜像,undolog记录的逻辑。多个 SQL 或复杂语句(如 batch SQL)会由 MultiExecutor 处理。
在这里插入图片描述
   最终执行 SQL:在这里插入图片描述

二、Seata代理增强

   在BaseTransactionalExecutorexecute方法中,首先会拿到xid并且绑定到当前的链接上。如果某个分支事务,不想加入到Seata的全局事务中,可以在执行自己的数据库操作逻辑前,对xid进行解绑,执行完成数据库操作后,再将xid绑定到当前线程。
在这里插入图片描述
  拿到代理链接,如果当前事务是自动提交,则会进入executeAutoCommitTrue分支:

在这里插入图片描述
  在executeAutoCommitTrue分支中,有三个重要的方法:

  • connectionProxy.changeAutoCommit();设置事务非自动提交
  • executeAutoCommitFalse获得前置镜像,后置镜像,执行目标sql,以及写入undolog。
  • connectionProxy.commit()数据库本地提交事务,向TC注册分支事务信息。

在这里插入图片描述

2.1、executeAutoCommitFalse

  executeAutoCommitFalse是获得前置镜像,后置镜像,执行目标sql,以及写入undolog的逻辑:
在这里插入图片描述

SQL 类型前置镜像(Before Image)后置镜像(After Image)作用说明
INSERT❌ 无(插入之前不存在)✅ 插入后的记录回滚时删除插入的记录
DELETE✅ 被删除前的记录❌ 无(删除后记录已不存在)回滚时重新插入被删除的数据
UPDATE✅ 更新前的记录(包括主键、字段值)✅ 更新后的记录回滚时根据 PK 恢复原数据
SELECT❌ 无❌ 无不需要,读取不会产生事务性修改
SELECT … FOR UPDATE✅(用于全局锁定判断)❌ 通常无后置镜像用于加锁,不影响数据内容

  以UPDATE的操作为例,说明一下源码中是如何生成前置和后置镜像的。

2.1.1、生成前置镜像

  选择如图的实现:在这里插入图片描述

在这里插入图片描述
  首先通过 getTableMeta()方法,获取先前缓存的数据库表元信息,包括表名,所有的字段名,索引等信息。
,
  然后通过buildBeforeImageSQL方法构建前置镜像:
在这里插入图片描述
  最终生成一条类似于下面的SQL语句,加上FOR UPDATE相当于给查询出的结果加上了行锁,避免其他线程并发修改。

SELECT col1, col2, col3 FROM table_name WHERE ... ORDER BY ... LIMIT ... FOR UPDATE

  最后执行buildTableRecords方法,执行传入的SELECT ... FOR UPDATE语句,并将查询结果(即将被修改的记录)封装为 Seata 内部统一格式TableRecords对象,用于生成 Undo Log。
在这里插入图片描述

2.1.2、生成后置镜像

在这里插入图片描述
  buildAfterImageSQL方法,是在UPDATE执行之后,根据主键把刚刚修改的数据查询出,作为后置镜像。类似于如下的SQL:

SELECT col1, col2 FROM table_name WHERE (id = ?) OR (id = ?)

  在buildRecords方法中同样将查询结果(即将被修改的记录)封装为 Seata 内部统一格式TableRecords对象,用于生成 Undo Log。

2.1.3、生成undolog

  生成undolog前,会进行判断,如果前置镜像和后置镜像都为空,那就没有必要生成undolog了。同样地,在update的场景下,如果前置镜像的行数和后置镜像的行数不相同,说明是有问题的,可能存在并发冲突。
在这里插入图片描述
  这里只是对undolog进行的缓存,并没有写到数据库
在这里插入图片描述

总结

  Seata 通过对客户端数据源进行代理增强,实现了在 SQL 执行前后生成前置镜像(Before Image)和后置镜像(After Image),并构建 UndoLog,以支持分布式事务的自动回滚能力。同时,在本地事务执行过程中会与 TC(Transaction Coordinator)协作,完成分支事务的注册和资源锁定。

  在 Spring Boot 应用启动阶段,Seata 利用自动配置机制向 Spring 容器中注册了一个 SeataAutoDataSourceProxyCreator 类型的 Bean。该类继承自 AbstractAutoProxyCreator,重写了 wrapIfNecessary 方法。在该方法中通过调用 buildProxy,将业务数据源封装为 DataSourceProxy 实例,从而实现数据源的代理。

  DataSourceProxy 的核心方法 getConnection() 返回的是一个增强后的连接对象 ConnectionProxyConnectionProxy 继承自 AbstractConnectionProxy,其重写的 prepareStatement() 方法会返回一个 PreparedStatementProxy 实例。在执行业务 SQL 时,实际调用的是其 execute() 方法,Seata 就是在这里织入了对事务的控制逻辑。

  具体而言,execute() 方法的执行过程如下:

  1. 绑定全局事务 XID 到当前数据库连接;
  2. 设置连接为非自动提交;
  3. 根据 SQL 类型解析器获取增强执行器(如 UpdateExecutorInsertExecutor 等);
  4. 构建并执行前置镜像查询(Before Image);
  5. 执行目标 SQL;
  6. 构建后置镜像查询(After Image);
  7. 基于镜像差异构建 UndoLog,并写入 undo_log 表;
  8. 提交本地事务;
  9. 向 TC 注册分支事务和对应的资源锁信息。

  通过这一整套机制,Seata 实现了对数据库操作的透明增强,使业务开发者无需关注底层事务控制细节,即可实现强一致性的分布式事务管理。

http://www.xdnf.cn/news/250723.html

相关文章:

  • Laravel 12 实现 OAuth2 登录
  • 鼎讯信通 智能通信干扰设备:多频段多模态信号压制解决方案
  • 【C++11】智能指针
  • 【学习笔记】机器学习(Machine Learning) | 第五章(2)| 分类与逻辑回归
  • 第 12 届蓝桥杯 C++ 青少组中 / 高级组省赛 2021 年真题
  • Python3 基本数据类型
  • Python 常用内置函数详解(八):对象属性操作getattr()、setattr()、delattr()、hasattr()、vars()函数详解
  • 【经管数据】上市公司企业资本要素和劳动要素投入数据(2000-2022年)
  • Memory Bank 不够用?Cline 全新 CRCT:省 token,依赖关系自行追踪
  • 如何解决 H5 远程收款的问题呢?
  • 目标文件的段结构及核心组件详解
  • 多线程系列二:Thread类
  • Window通过虚拟机17安装Ubuntu20.04并安装相关的插件(胎教级教程)
  • 回归树:从原理到Python实战
  • 【C语言】文本操作函数fseek、ftell、rewind
  • 详细介绍Python-pandas-DataFrame全部 功能 函数
  • 存储器层次结构:理解计算机记忆的金字塔
  • 23页PDF | 数据治理实施方案 :规划、执行、评价、改进四步走的管控模式
  • Seata服务端开启事务核心源码解析
  • 位运算题目:寻找重复数
  • 最长公共前缀(14)
  • 基于Koa实现的服务端渲染 ✅
  • 8.进程概念(四)
  • 为什么大模型偏爱Markdown
  • 操作系统(1)多线程
  • 【Machine Learning Q and AI 读书笔记】- 03 小样本学习
  • 数字智慧方案6178丨智慧医院医疗信息化建设之以评促建(61页PPT)(文末有下载方式)
  • 微型计算机串行通信实验三全解析:从原理到实践的探索之旅
  • 《数字图像处理(面向新工科的电工电子信息基础课程系列教材)》章节思维导图
  • 【验证技能】文档要求和好文档注意点