ConnectionProxy#changeAutoCommit()
文章插图
现在事务自动提交已经被Seata改成false了
文章插图
UpdateExecutor#beforeImage()
文章插图
BaseTransactionalExecutor#prepareUndoLog()
文章插图
接下来,提交事务
ConnectionProxy#commit()
文章插图
ConnectionProxy#processGlobalTransactionCommit() 处理全局事务提交
文章插图
分支事务提交以后,业务数据更改和undo_log就都提交了
回想一下,为什么在执行业务修改前要先将默认的自动提交改成手动提交 , 最后再改成自动提交呢?
因为 , 要将业务数据修改和插入undo_log放在同一个事务里,一起提交
这一切都归功于代理
回顾一下整个调用链
文章插图
结合之前的案例,AT模式TC、TM、RM三者的交互应该是这样的:
文章插图
问题一:为什么在执行的时候,先将数据库自动提交autoCommit设为false,最后再改成true呢?
答:因为,需要将undo_log和业务数据修改放到同一个事务中,这样可以保证业务数据修改成功后undo_log必然插入成功,所以Seata要将其改为手动提交 。最后再改成true是因为默认autoCommit就是true , 这样可以不影响其它业务 。
问题二:什么情况下ConnectionContext中xid=null,且isGlobalLockRequire=true呢?或者换一种问法 , 什么情况下不在全局事务中 , 当仍然需要全局锁呢?
答:当业务方法上不加@GlobalTransactional,而是只加了@GlobalLock注解的情况下 , 就会出现上述情况,也就会执行 ConnectionProxy#processLocalCommitWithGlobalLocks()方法,在事务提交前检查全局锁,这样设计的目的是在AT模式下,不出现脏读、脏写 。由于数据源被代理了,当一个加了@GlobalTransactional的全局事务 , 与另一个加了@GlobalTransactional或@GlobalLock注解的事务在本地事务提交前就会检查全局锁 , 要先获得全局锁才能提交本地事务,这样就避免了脏读脏写,从而相当于实现了全局事务的读已提交隔离级别 。参见:https://seata.io/zh-cn/blog/seata-at-lock.html
关于Seata 1.5.2 Client端的源码学习就先到这里,欢迎交流~
如果你都已经看到了这里 , 不妨给我点个赞吧
推荐阅读
- .NET 源码学习 [数据结构-线性表1.2] 链表与 LinkedList<T>
- Redisson源码解读-公平锁
- OpenHarmony移植案例: build lite源码分析之hb命令__entry__.py
- 【深入浅出 Yarn 架构与实现】1-2 搭建 Hadoop 源码阅读环境
- Redisson源码解读-分布式锁
- 源码级深度理解 Java SPI
- Dubbo-聊聊通信模块设计
- 【lwip】10-ICMP协议&源码分析
- 【lwip】09-IPv4协议&超全源码实现分析
- 从BeanFactory源码看Bean的生命周期