这是我参与2022首次更文挑战的第10天,活动详情查看2022首次更文挑战
Seata AT模式的实现原理
AT模式是基于XA事务模型演进而来的,它的整体机制是一个改进版的两阶段提交协议。
- 第一阶段:业务数据和回滚日志记录在同一个本地事务中提交,释放本地锁和连接资源。
- 第二阶段:提交异步化,快速完成,回滚通过第一阶段的回滚日志进行反向补偿。
AT模式第一阶段的实现原理
在业务流程中执行库存扣减操作的数据库操作,Seata会基于数据源代理对原执行的SQL进行解析,代理的配置代码如下(Seata 0.9.0版本后支持自动代理)
@Bean
public DataSourceProxy DataSourceProxy(DruidDataSource druidDataSource){
return new DataSourceProxy(druidDataSource);
}
将业务数据在更新数据前后保存在undo_log日志表中,利用本地事务的ACID特性,把业务数据的更新和回滚日志写入同一个本地事务中进行提交,完整的执行流程如下图所示:
库存表结构
| id | product_code | name | count |
|---|---|---|---|
| 1 | 20220129160001 | 鼠标 | 1000 |
| 2 | 20220129160002 | 键盘 | 500 |
AT分支事务业务逻辑是
update stock set count = count - 1 where product_code = "20220129160002"
第一阶段的执行逻辑
-
通过DataSourceProxy对业务SQL进行解析,得到SQL类型(update)、表(stock)、条件(where product_code = "20220129160002" )等相关的信息。
-
查询修改之前的数据镜像,根据解析得到的条件信息生成查询语句,定位数据。
select id,product_code,name,count from stock where product_code = "20220129160002"查询获取产品对应的库存数量为1000。
-
执行业务SQL,更新记录的count=count-1
-
查询修改后的数据镜像,根据前镜像的结果,通过主键定位数据。
select id,product_code,name,count from stock where id = 2
得到修改后的镜像数据count=999。
-
插入回滚日志,把前、后镜像数据及业务SQL相关的信息组成一条回滚日志记录,插入undo_log表中,可在对应库的undo_log表中获得数据。
undo_log表数据如下:
id branch_id xid context rollback_info log_status log_created log_modified 1 20220129162201 10.0.101.175:8091:202201291623 serializer=jackson (BLOB) 0 2022-01-29 16:26:39 2022-01-29 16:26:39 注意:rollback_info标识回滚的数据包含beforeImage和afterImage。
-
提交前,向TC注册分支事务,申请stock表主键值等于1的记录的全局锁。
-
本地事务提交:业务数据的更新和生成的undo_log一并提交。
-
将本地事务提交的结果上报给TC。