Seata AT解决脏写问题
2022-07-06 15:25:01 13 举报
Seata AT解决脏写问题
作者其他创作
大纲/内容
updateAll
注册分支事务,获取全局锁
undolog和业务数据一起入库
查询前置镜像
捕获锁冲突异常后,回滚,释放本地锁,尝试重新竞争本地锁
发生脏写的情况
发现全局锁被占用了,无法提交,抛出锁冲突异常
数据库提交
等待本地锁
执行业务sql
业务二
解决方案二:@GlobalLock+select for update
准备undolog
数据入库,数据库提交
解决方案一:在updateA上也加上@GlobalTransactional
释放本地锁
获得本地锁
updateB()
查询后置镜像
业务一
updateA
查询全局锁。如果全局锁已被占用,则抛出锁冲突异常
业务一调用updateAll,业务二直接调用updateA
updateA()
如果updateB发生异常,要全局回滚,A记录并没有被业务二修改(执行了但没法提交,所以数据库的数据没有被修改),可以全局回滚
如果updateB发生异常,要全局回滚,但A记录已经被业务二修改了,发生了脏写,导致全局无法回滚
class YourBussinessService { DbServiceA serviceA; DbServiceB serviceB; @GlobalTransactional public boolean updateAll(DTO dto) { serviceA.update(dto.getA()); serviceB.update(dto.getB()); } public boolean updateA(DTO dto) { serviceA.update(dto.getA()); }}class DbServiceA { @Transactional public boolean update(A a) { }}
class YourBussinessService { DbServiceA serviceA; DbServiceB serviceB; @GlobalTransactional public boolean updateAll(DTO dto) { serviceA.update(dto.getA()); serviceB.update(dto.getB()); } @GlobalLock public boolean updateA(DTO dto) { serviceA.selectForUpdate(dto.getA()); serviceA.update(dto.getA()); }}class DbServiceA { @Transactional public boolean update(A a) { }}
释放全局锁
可能会等待本地锁超时
class YourBussinessService { DbServiceA serviceA; DbServiceB serviceB; @GlobalTransactional public boolean updateAll(DTO dto) { serviceA.update(dto.getA()); serviceB.update(dto.getB()); } @GlobalTransactional public boolean updateA(DTO dto) { serviceA.update(dto.getA()); }}class DbServiceA { @Transactional public boolean update(A a) { }}
select for update
获得全局锁,更新A
全局完成,释放全局锁
0 条评论
下一页