原文链接:SpringCloud~分布式事务~Seata~AT模式 – 编程屋
目录
1 概述
对于单体服务来说,我们只需要在方法上加上@Transactional注解就可以保证事务的顺利进行,但是对于我们的分布式来说,它涉及到多个服务,服务之间的相互调用没有一个统一的感知,导致了我们某个服务出错了,其他服务的功能有时依然正常进行。所以需要引入分布式事务来保证我们的事务 ,某个服务出错了,相应服务间的调用能够正常进行回滚操作。
seata有好几种模式(AT模式、TCC模式、Saga模式和XA模式),本篇文章讲述seata框架下的AT模式
2 AT模式
Seata开源了AT模式。AT模式是一种无侵入式的分布式解决方案。可以看做是对TCC或者二阶段提交模型的一种优化,解决了TCC模式中的代码侵入,编码复杂等问题。
在AT模式下,用户只需关注自己的业务sql,用户的业务sql作为第一阶段,Seata框架会自动生成事务的二阶段的提交和回滚操作。
2.1 基本原理
流程图:
可以看出,AT模式和之前说过了TCC模式很相似,都是分为了两个阶段。
第一阶段:执行本地事务,并返回执行结果
第二阶段:根据第一阶段的结果,判断二阶段的做法:提交还是回滚
但与TCC模式有很大不同的是,第二阶段的操作完全不需要我们去操作,Seata自己就可以实现了。换句话说:引用的AT模式后,我们写的代码和之前的本地事务一样,完全不需要手动的去处理分布式事务。
既然AT模式实现了代码的无侵入性,那么是如何实现在第二阶段是自动提交还是自动回滚呢?
如何实现自动回滚或提交操作的?
第一阶段:
在第一阶段。Seata回拦截业务sql,首先解析sql语义,找到业务sql要更新的业务数据,在业务sql更新前,将其保存为"before image",然后执行业务sql,更新业务数据之后,再将其保存为"aftr image",最后获取全局行锁,提交事务。以上操作全部在一个数据库事务内完成,这样保证了一阶段操作的原子性。
二阶段
1)提交:二阶段如果是提交的话,因为“业务sql”在第一阶段已经提交到数据库,所以Seata框架只需要将第一阶段保存的快照数据和行锁删掉,完成数据清理即可。
2)回滚:二阶段如果回滚,Seata就需要回滚一阶段已经执行的业务sql,还原业务数据。回滚数据就是用“before image”还原业务数据;但在还原前需要校验脏写,对比数据库当前业务数据和“after image”,如果两份数据完全一样说明没有脏写,可以还原业务数据,如果不一致就说明有脏写,出现脏写就需要人工手动处理。
举例:
业务sql:update storage set count = count -1 where id = 1;
此时如果想要执行上述的一个业务sql
在第一阶段时,
- seata会拦截当前sql,
- sql执行前,找到所对应的数据库表,将id = 1 的这条数据记录下来,生成一个快照“before image”
- sql执行后,将执行后对应的数据库记录记录下来,生成一个快照“after image”
- 生成行锁,提交记录
在第二阶段时,
- 看对应的事务是否全部提交成功,如果是将第一阶段保存的快照数据和行锁删掉,完成数据清理
- 如果有事务提交失败,根据before image还原业务数据,还原之前需要拿记录数据和当前数据进行比对,防止脏数据
2.2 相关角色
Seata中有三大模块,分别是TM、RM和TC.其中TM和RM是作为Seata的客户端与业务系统紧密联系在一起,TC作为Seata的服务器独立部署。
TC-事务协调者:维护全局和分支事务的状态,驱动全局事务提交和回滚
TM-事务管理器:定义全局事务范围:开始全局事务,提交或回滚全局事务
RM-资源管理器:管理分支事务处的资源,与TC交谈以注册分支事务和报告分支事务的状态,并驱动分支事务提交和回滚
其中TC是一个独立的服务,需要单独引进,而TM和RM则需要引入jar包就可以。
3 代码实战
3.1 SpringCloud
注:为了方便,此实战代码是直接网上找来的,亲测可用
demo介绍:springcloud搭建,eureka为注册中心,包含了三个微服务(库存服务,订单服务,账户服务)
场景介绍;下单时,订单服务调用账户服务和库存服务,这样就会产生跨服务和跨服务员的分布式事务问题。
简单介绍下服务间的相互调用:
订单服务:
以上只是部分内容,为了维护方便,本文已迁移到新地址:SpringCloud~分布式事务~Seata~AT模式 – 编程屋