Seata执行整体流程(AT模式)| Seata源码 - 自动配置数据库代理 | AT和XA的区别
Posted 做猪呢,最重要的是开森啦
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Seata执行整体流程(AT模式)| Seata源码 - 自动配置数据库代理 | AT和XA的区别相关的知识,希望对你有一定的参考价值。
0. 相关术语:
- TC一般指seata-server
- TM一般就是事务操作接口入口的服务,也就是标注@GlobalTransactional的服务
- RM一般就是涉及整体事务操作的服务
- 比如确认订单加积分,订单服务就作为TM和RM,积分服务就作为RM
实验代码可见GitHub
1. 整体流程:
- TM、RM注册
- 初始化后置处理器方法中引入全局事务拦截器GlobalTransactionalInterceptor
- 请求时调用拦截器invoke方法,TM发起全局事务
- RM通过数据库代理执行本地事务
- 解析SQL - 关闭自动提交 - 查询前镜像 - 执行业务SQL - 查询后镜像 - 根据前后镜像构建undo_log - 提交写入undo_log - 手动提交业务SQL
- TM发送commit/rollback给TC
- 分支事务提交/回滚:
- 如果提交:采用异步线程去删除undo_log,一阶段已经提交本地事务了
- 如果回滚:根据分支事务id和全局事务xid获取undo_log(数据库表有唯一索引),然后进行反向补偿,删除undo_log
1.1. TM、RM注册
- 自动配置类SeataAutoConfiguration引入GlobalTransactionScanner
- GlobalTransactionScanner实现InitializingBean,在IOC创建bean时,会调用afterPropertiesSet方法
- 内部调用initClient方法中,进行TM、RM注册
1.2. 引入全局事务拦截器GlobalTransactionalInterceptor
- GlobalTransactionScanner继承了AbstractAutoProxyCreator,是个后置处理器,并重写了wrapIfNecessary方法
- 在IOC创建bean时,会调用postProcessAfterInitialization后置处理器方法,然后执行wrapIfNecessary
- 引入全局事务拦截器GlobalTransactionalInterceptor
1.3. 请求时调用拦截器invoke方法,TM发起全局事务
- 当发起请求,再调用Controller时会先调用拦截器,也就是全局事务拦截器GlobalTransactionalInterceptor的invoke()方法
- 如果要发起全局事务就调用handleGlobalTransaction方法
- 调用transactionalTemplate.execute方法,进行事务创建/加入,发起全局事务
beginTransaction是一个模板方法,tx.begin发起全局事务会生成和绑定全局事务xid
1.4. RM通过数据库代理执行本地事务:
- beginTransactionf发起全局事务后,business.execute()最终反射调用@GlobalTransactional注解的方法
- 当业务方法中进行数据库操作时,seata通过数据库代理执行
- 解析SQL - 关闭自动提交 - 查询前镜像 - 执行业务SQL - 查询后镜像 - 根据前后镜像构建undo_log - 提交写入undo_log - 手动提交业务SQL
1.4 .1. 启用数据库自动代理:
- 此处seata-all是1.4.2版本,需要在启动类加上@EnableAutoDataSourceProxy注解
- 最终是会注册两个bean:SeataDataSourceBeanPostProcessor、SeataAutoDataSourceProxyCreator
- bean创建SeataDataSourceBeanPostProcessor时,调用后置处理器方法进行数据源代理(DataSourceProxy)
- 数据源获取Connection 的时候,也会对Connection 进行代理(ConnectionProxy):
- 通过ConnectionProxy获取statement时(父类AbstractConnectionProxy方法),seata也对statement进行了代理;
1.4 .2. 数据源代理执行SQL:
- seata对数据源到statement都进行了代理,当statement执行SQL时,最终调用ExecuteTemplate.execute核心方法
调用链:
- executor.execute → io.seata.rm.datasource.exec.BaseTransactionalExecutor#doExecute → executeAutoCommitTrue
- executeAutoCommitFalse(args) → connectionProxy.commit(); → doCommit → processGlobalTransactionCommit
执行流程:
- 解析 SQL:得到 SQL 的类型、表、条件等相关的信息
- 关闭自动提交
- 查询前镜像(原始数据):根据解析得到的条件信息,生成查询语句,定位数据。
- 执行业务 SQL
- 查询后镜像(修改后数据):根据前镜像的结果,通过 主键 定位数据。
- 构建undo_log日志
- 提交写入undo_log日志
- 手动提交业务SQL,本地事务也提交了,但全局事务没有
1.5 TM发送commit/rollback给TC:
- RM执行完本地事务(也就是业务方法执行完),都执行正常TM就发送commit给TC,否则就rollback
- 通过全局事务xid控制commit/rollback
1.7 分支事务提交/回滚:
- 如果提交:采用异步线程去删除undo_log,一阶段已经提交本地事务了
- 如果回滚:根据分支事务id和全局事务xid获取undo_log(数据库表有唯一索引),然后进行反向补偿,删除undo_log
- 详情可以见参考链接:seata客户端二阶段分支事务的提交和回滚
2. AT和XA的区别:
核心区别在于:
- AT模式一阶段本地事务提交完后会提交本地事务;
- XA模式要在所有的本地事务执行完成后,TC才发送指令让所有的RM提交事务、释放本地锁。
- 所以XA的性能会低,但能保证强一致性效果
以上是关于Seata执行整体流程(AT模式)| Seata源码 - 自动配置数据库代理 | AT和XA的区别的主要内容,如果未能解决你的问题,请参考以下文章