前言
本篇文章是我第一次输出分布式事务相关文章,只是对Seata的AT模式代码实现设计做一个概要分析,AT模式特别注意以下方面
- 基于支持本地 ACID 事务的关系型数据库
- Java 应用,通过 JDBC 访问数据库
- 全局事务角色信息:GlobalTransactionRole
- Launcher
- Participant
整体机制
两阶段提交协议的演变:
- 一阶段:业务数据和回滚日志记录在同一个本地事务中提交,释放本地锁和连接资源
- 二阶段:
2.1 提交异步化,非常快速地完成
2.2 回滚通过一阶段的回滚日志进行反向补偿
简单使用
- 按照官方文档说明,分别启动seata-server、account、order、Storege服务
- 启动测试用例:DubboBusinessTester#main
源码分析
@GlobalTransactional:Launcher发起全局事务
- @GlobalTransactional注解拦截处理:GlobalTransactionalInterceptor#handleGlobalTransaction
- 模板方法TransactionalTemplate#execute
2.1 模板方法流程总结:
(1)通过@GlobalTransactional获取事务信息txInfo
(2)获取全局事务GlobalTransaction:tx
(3)对txInfo的传播属性做处理
(4)发送事务开启请求到TC,返回事务ID:xid
(5)执行业务方法
(6)所有业务执行完后,提交事务
Participant参与事务
- Participant是怎样参与到全局事务的?
1.1 通过下图发现seata客户端在数据源做了一层代理,在执行jdbc方法时会被增强处理
- 主要逻辑在ExecuteTemplate#execute
2.1 获取全局事务ID:xid (下面会分析xid是如何传播的)
2.2 执行本地更新操作
2.2 通过更新操作前后表数据TableRecords生成回滚日志:SQLUndoLog
2.3 向TC发送分支注册请求BranchRegisterRequest,返回branchId
2.4 提交本地事务
- 全局事务ID(xid)传播:AlibabaDubboTransactionPropagationFilter
3.1 发起者Launcher在TC申请到xid,设置到RpcContext中
3.2 协作者Participant从RpcContext取出全局事务IDString xid = RootContext.getXID(); RpcContext.getContext().setAttachment(RootContext.KEY_XID, xid);
String rpcXid = rpcXid = RpcContext.getContext().getAttachment(RootContext.KEY_XID.toLowerCase()); if (rpcXid != null) { RootContext.bind(rpcXid); }
TC处理全局事务请求
- 处理版本注册请求
- 处理事务提交请求