Seata---AT模式会不会出现脏读

一句话回答:会出现一种脏读情况,只不过和传统脏读不一样

一句话回答:会出现一种脏读情况,只不过和传统脏读不一样,传统的脏读指的是读取到其他(MySQL本地事务)事务未提交的数据。而Seata会出现,读取到其他(分支事务)(本地事务)事务已提交但可能被全局回滚的数据。

(听上去有点绕?你看完下面的介绍在回过头来看,就能明白了。。。)

想要回答好这个问题,需要先了解一下Seata的AT模式的工作原理。

AT模式的核心机制是两阶段提交:

●第一阶段:本地事务立即提交,释放本地锁,数据对其他事务可见。 ●第二阶段:全局事务根据协调结果决定提交或回滚(通过undo log补偿)。

那么,大家仔细想一下这个场景,其实会出现一种情况,那就是如果全局事务最终回滚,其他事务可能在P第一阶段结束后、第二阶段回滚前读取到已提交但即将被撤销的数据,导致逻辑上的脏读。

案例

现在有三个模块,交易模块、订单模块和库存模块。在一次下单过程中,为了保证一致性,代码可能如下:

java 复制代码
import io.seata.spring.annotation.GlobalTransactional;
import org.springframework.beans.factory.annotation.Autowired;

@Service
public class TradeService {
    @Autowired
    private InventoryService inventoryService;
    @Autowired
    private OrderService orderService;

    @GlobalTransactional
    public boolean buy() {
        //库存扣减   
        inventoryService.decreaseInvenroty();       
        //创建订单   
        orderService.createOrder();  }  
    }

在这个分布式事务中(@GlobalTransactional开启的分布式事务),先调库存服务进行库存扣减,然后再调用订单服务进行订单创建。那么整个(大致)流程就是这样的:

这里需要注意的是,在第二步调库存模块之后,库存模块的在数据库上的操作,都是基于数据库的本地事务的,他需要通过数据库的本地事务来保障undolog(Seata用到的的undolog,和MySQL中MVCC的那个undolog不是一个)和库存扣减的原子性,并且这一步执行完之后,数据库的本地事务是要做提交的!

这很关键,数据库的本地事务做了提交,事务提交了,也就意味着,不管在什么样的事务隔离级别下,其他的事务都能查到提交后的新值了。

那么试想一下,如果在第二步执行成功之后,库存已经完成了扣减,但是第三步执行订单创建执行失败了,这时候整个分布式事务是要回滚的,那么就会基于库存库中的undolog做回滚。那么,在提交后,回滚前,如果有其他的事务来查询库存数据,是不是就读到了一个本该回滚的值?

这是不是也是一种脏读,只不过这个脏读并不是MySQL的本地事务中的脏读,而是Seata全局事务中的脏读。即在全局事务过程中,别的事务可能会读到全局事务尚未提交(后面可能会回滚)的数据。

AT如何避免脏读

AT模式的脏读是他的实现机制导致的,因为他的第一阶段是借助分支事务实现的,利用分支事务的ACID保证业务操作和undolog的写入的原子性。但是第一阶段执行完,整个全局事务并没有确定要不要提交,还是有可能会回滚的。一旦发生回滚,那么在回滚前,就会能读到脏数据了。

那么这个问题如何避免呢?

也有一个办法解决 就是在查询的时候加上 @GlobalTransactional + select * ... for update 但是这个比较笨拙 但是确实可以解决这个棘手的问题

在就没啥好办法,因为事务已经提交了,没办法避免其他事务的读取,就算能实现,也会大大降低可用性。所以如果不能接受脏读,那么不要使用AT模式,可以选择其他的事务方案,比如TCC。

相关推荐
无相求码3 分钟前
为什么你的第二个 scanf 还没输入就直接跳过了?C语言输入缓冲区陷阱
c语言·后端
叼馒女友郭芙蓉3 分钟前
Function Calling理解
后端
玉宇夕落4 分钟前
LangChain RAG Retriever 的学习
后端
用户2986985301410 分钟前
Python 一键导出 Excel 中的图表和形状为图片
后端·python·excel
用户81300778163712 分钟前
PageHelper分页查询步骤
后端
是小李呀14 分钟前
MyBatis、MyBatis-Plus 与全自动 ORM 的本质区别
后端
小堂子这厢有礼了27 分钟前
Chet.Admin 权限模型:菜单级 + 按钮级 + 行级三层防护
前端·后端·信息可视化·前端框架·.net
SimonKing28 分钟前
Spring Boot 4.0 + gRPC 极简集成:4步搞定,比REST还丝滑
java·后端·程序员
IT_陈寒1 小时前
Vue的这个响应式陷阱,让我加班到凌晨三点
前端·人工智能·后端
Wang's Blog1 小时前
Go-Zero基础入门5: 探究go-zero如何基于gRPC扩展客户端
开发语言·后端·golang·go-zero