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。

相关推荐
还听珊瑚海吗34 分钟前
基于SpringBoot的抽奖系统测试报告
java·spring boot·后端
你怎么知道我是队长3 小时前
Go语言标识符
后端·golang
sco52827 小时前
SpringBoot 自动装配原理 & 自定义一个 starter
java·spring boot·后端
海风极客8 小时前
《Go小技巧&易错点100例》第三十三篇
开发语言·后端·golang
养军博客8 小时前
Spring boot 简单开发接口
java·spring boot·后端
计算机学姐11 小时前
基于SpringBoot的在线教育管理系统
java·vue.js·spring boot·后端·mysql·spring·mybatis
有梦想的攻城狮11 小时前
spring中的@Value注解详解
java·后端·spring·value注解
编程乐趣12 小时前
基于.Net Core开发的GraphQL开源项目
后端·.netcore·graphql
阿乾之铭13 小时前
Spring Boot 中的重试机制
java·spring boot·后端
LUCIAZZZ14 小时前
JVM之内存管理(二)
java·jvm·后端·spring·操作系统·springboot