机制
两阶段提交协议的演变:
- 一阶段:业务数据和回滚日志记录在同一个本地事务中提交,释放本地锁和连接资源。
- 二阶段:
- 提交异步化,非常快速地完成。
- 回滚通过一阶段的回滚日志进行反向补偿。
集成过程
工作机制
一阶段
- 根据update语句的条件组成select脚本,查询得到更改前的数据记录;
- 执行update语句,更改数据库数据记录;
- 根据数据记录的主键,查询得到更改后的数据记录;
- 将update语句执行前后的数据记录组装成一条回滚日志记录,插入到 undo_log 表中;
- 提交本地事务前,向TC注册分支,并根据修改的数据记录主键申请记录数据表的全局锁;
- 提交本地事务,完成业务数据记录和undo_log表的更新;
- 将本地事务的提交结果上传给TC。
二阶段-回滚
- 收到TC的分支回滚请求,开启一个本地事务;
- 通过xid和branch_id查找到相应的undo_log记录;
- 数据校验:拿undo_log中的修改后记录与当前数据进行比较,如果有不同,说明数据被当前全局事务之外的动作做了修改,需要根据配置策略来做处理;
- 根据undo_log中的前记录和业务SQL的相关信息生成并执行回滚的语句;
- 提交本地事务。并把本地事务的执行结果(即分支事务回滚的结果)上报给 TC。
二阶段-提交
- 收到 TC 的分支提交请求,把请求放入一个异步任务的队列中,马上返回提交成功的结果给 TC。
- 异步任务阶段的分支提交请求将异步和批量地删除相应 UNDO LOG 记录。
写隔离(针对同一业务场景的高并发)
- 分支事务执行时先读取本地事务锁,全局隔离级别是为“读未提交”(默认)
- 执行分支UPDATE命令
- 获取全局事务锁
- 提交本地事务,释放本地事务锁
-
- 成功-提交全局事务、释放全局事务锁
- 失败-回滚本地事务
图例
- 成功
- 失败
读隔离(针对不同业务场景的脏读)
针对 FOR UPDATE 的 SELECT 语句做代理获取全局锁;分支事务在执行时首先通过该语句请求全局锁,获取到全局锁后才开始事务的执行。
例图
特征
- 优点:借助于关系数据库的ACID事务,使用便捷,通过引入undo_log表存储回滚数据,同时保证了可用性和一致性
- 缺点:分支事务需要先进行提交,影响执行效率,无法支持非关系型数据库
#参考文献
Seata AT模式