基本信息
文件名称:Spring Cloud Seata系列:基于AT模式实现分布式事务.docx
文件大小:17.25 KB
总页数:4 页
更新时间:2025-05-22
总字数:约2.55千字
文档摘要

SpringCloudSeata系列:基于AT模式实现分布式事务

以一个示例来说明:

两个全局事务tx1和tx2,分别对a表的m字段进行更新操作,m的初始值1000。

tx1先开始,开启本地事务,拿到本地锁,更新操作m=1000-100=900。本地事务提交前,先拿到该记录的全局锁,本地提交释放本地锁。tx2后开始,开启本地事务,拿到本地锁,更新操作m=900-100=800。本地事务提交前,尝试拿该记录的全局锁,tx1全局提交前,该记录的全局锁被tx1持有,tx2需要重试等待全局锁。

tx1二阶段全局提交,释放全局锁。tx2拿到全局锁提交本地事务。

如果tx1的二阶段全局回滚,则tx1需要重新获取该数据的本地锁,进行反向补偿的更新操作,实现分支的回滚。

此时,如果tx2仍在等待该数据的全局锁,同时持有本地锁,则tx1的分支回滚会失败。分支的回滚会一直重试,直到tx2的全局锁等锁超时,放弃全局锁并回滚本地事务释放本地锁,tx1的分支回滚最终成功。

因为整个过程全局锁在tx1结束前一直是被tx1持有的,所以不会发生脏写的问题。

在数据库本地事务隔离级别读已提交(ReadCommitted)或以上的基础上,Seata(AT模式)的默认全局隔离级别是读未提交(ReadUncommitted)。

如果应用在特定场景下,必需要求全局的读已提交,目前Seata的方式是通过SELECTFORUPDATE语句的代理。

SELECTFORUPDATE语句的执行会申请全局锁,如果全局锁被其他事务持有,则释放本地锁(回滚SELECTFORUPDATE语句的本地执行)并重试。这个过程中,查询是被block住的,直到全局锁拿到,即读取的相关数据是已提交的,才返回。

出于总体性能上的考虑,Seata目前的方案并没有对所有SELECT语句都进行代理,仅针对FORUPDATE的SELECT语句。

AT模式的优点:

一阶段完成直接提交事务,释放数据库资源,性能比较好

利用全局锁实现读写隔离

没有代码侵入,框架自动完成回滚和提交

AT模式的缺点:

两阶段之间属于软状态,属于最终一致

框架的快照功能会影响性能,但比XA模式要好很多

AT与XA的区别

简述AT模式与XA模式最大的区别是什么?

XA模式一阶段不提交事务,锁定资源;AT模式一阶段直接提交,不锁定资源。

XA模式依赖数据库机制实现回滚;AT模式利用数据快照实现数据回滚。

XA模式强一致;AT模式最终一致

实现AT模式

AT模式中的快照生成、回滚等动作都是由框架自动完成,没有任何代码侵入,因此实现非常简单。

只不过,AT模式需要一个表来记录全局锁、另一张表来记录数据快照undo_log。

1)导入数据库表,记录全局锁

导入undo_log表导入到微服务关联的数据库:

--forATmodeyoumusttoinitthissqlforyoubusinessdatabase.theseataservernotneedit.

CREATETABLEIFNOTEXISTS`undo_log`

`branch_id`BIGINTNOTNULLCOMMENTbranchtransactionid,

`xid`VARCHAR(128)NOTNULLCOMMENTglobaltransactionid,

`context`VARCHAR(128)NOTNULLCOMMENTundo_logcontext,suchasserialization,

`rollback_info`LONGBLOBNOTNULLCOMMENTrollbackinfo,

`log_status`INT(11)NOTNULLCOMMENT0:normalstatus,1:defensestatus,

`log_created`DATETIME(6)NOTNULLCOMMENTcreatedatetime,

`log_modified`DATETIME(6)NOTNULLCOMMENTmodifydatetime