TM的本身也是一个RM

先上一个时序图

用户 TM TC RM 发起请求 注册全局事务 返回xid TM切换RM 前镜像 execute 后镜像 生成undolog和全局锁的key 获取全局锁 持久化undolog commit提交事务 释放本地锁(此时全局锁依然存在) feign调用 前镜像 execute 后镜像 生成undolog和全局锁的key 获取全局锁 持久化undolog commit提交事务 释放本地锁(此时全局锁依然存在) 返回结果 全局提交或回滚 二阶段全局提交删除记录和全局锁如果回滚申请本地锁 返回请求 用户 TM TC RM

关于seata事务多次操作同一数据可能导致回滚异常的问题

分支事务回滚时 会根据全局事务xid到branch_table中按照记录生成的时间(gmt_create) 正序查询所有分支事件记录放入List中,之后从List里倒序取出,挨个执行回滚! 然后惊奇的发现 每次出现上述回滚异常 都是因为 有两条或多条branch_table记录的 gm_create是相同的 以致于后续回滚查询分支事务的时候 无法保证其先后顺序,而后执行回滚的顺序 就一样无法保证.
如上:无法保证顺序.除非修改源码.否则应该尽量避免一个大事务多次操作同一个数据.并且是在同一秒内
在这里插入图片描述

还有一个事务回滚问题

在事务本地锁已经释放的时候.全局锁还存在.假设还有一个线程执行任务.是可以获取到本地锁的.也有可能导致回滚的异常.可以加入@GLOBALLOCK解决问题.

seata如何解决全局事务回滚的死锁问题

如果是同样的加了GlobalTransactional的事务.
事务1获取本地锁执行完获取全局锁后释放本地锁.(此时全局锁依然在)
事务2获取到相同本地锁执行完后去获取全局锁.此时全局锁没有释放
假设任务失败需要回滚
事务1发起全局回滚此时需要获取本地锁回滚
但是事务2持有了本地锁去获取全局锁.
此时死锁形成.这种情况seata的解决方案是.优先释放事务2的本地锁.让事务1的全局锁能去执行回滚操作.

seata的全局锁到底是什么?

seata的全局锁类似行锁.也是对于记录的锁.
存在lock_table中 pk就是数据主键.对这个记录会进行锁定
在这里插入图片描述

总结

seata的性能其实比较差.但是对于全局事务的实现比较方便.在不考虑大批量新增更新操作的情况下是个很好的解决方案,但是要避坑.

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐