实现原理
- TM(发起方)会向我们的TC协调者申请一个全局的事务id,保存到threadlocal中;
- TM(发起方)和RM(参与方)都被Seata的数据数据源实现代理,在原生的sql之前和之后保存原来和修改后日志到undo_log中,方便后期实现回滚。
- TM(发起方)使feign客户端调用接口时候,在ThreadLoacl中获取xid,设置到请求头中;
- RM(参与方)从请求中获取到该xid,设置到ThreadLoacl中,同时也会向seataserver注册该分支事务。
- TM(发起方)将当前本地事务的结果,告诉给协调者TC,协调者TC在通知所有的分支是否回滚。
- TM(发起方)如果调用接口成功之后抛出异常的情况下,告诉给协调者TC,协调者TC在通知所有的分支根据根据全局的xid和分支事务的id 查询分支数据源的undo_log日志表逆向生成sql语句实现回滚,同时删除对应的undo_log日志
- TM(发起方)如果调用接口成功之后没有抛出任何的异常,告诉给协调者TC,协调者TC在通知所有的分支根据根据全局的xid和分支事务的id 查询分支数据源的 删除对应的undo_log日志表
前置镜像:(数据之前的样子【备份】)
后置镜像:(数据之后的样子【备份】)
如何逆向实现sql语句:
insert 逆向 delete
delete 逆向 insert
update 逆向 update
Seata与LCN的区别?
- 基本实现的思路是一样的,唯一区别在于回滚的方式 LCN采用代理数据源假关闭连接,暂时不提交本地事务,但是容易造成数据的死锁。
- Seata采用undo_log的形式逆向生成sql语句实现回滚,避免死锁现象但是容易出现脏读。
源码分析
AOP入口类分析
- 项目中会引入到SpringCloud-Alibaba-seata. jar执行spring. factories 配置中读取 Globa ITransactionAutoConfiguration 配置类,会加载到GlobaITransactionScanner 到Spring的容器中。
- G loba ITransact i onScanner实现了AbstractAutoProxyCreator、InitializingBean 接口。
Abstr actAutoProxyCreator: SpringAOP原生类创建代理对象。
InitializingBean:SpringBena生命周期初始化
GlobalTransactionScanner:对象初始化成功之后开始注册我们的 tm和 tc 到全局协调者中去。
AbstractAutoProxyCreator 回调的方法 wrapIfNecessary 创建我们的 GlobaITransactionalInterceptor.
执行发起方方法前会执行我们的 GlobaITransactionalInterceptor 的 invoke 方法,判断有没有加上全局事务注解,再执行我们的transactionaITemplate的execute 方法,
处理分布式事务的核心方法:
发起方在方法上面加上@GlobaITransactional,会被aop拦截.
创建全局事务id(xid)
开启事务方法
发送请求给TC创建xid
前置镜像和后置镜像
查找对于源码的方法,可以将数据库中的UNDO_LOG表删除,根据报错信息查找。
存入UNDO_LOG表数据