行业资讯 2025年08月6日
0 收藏 0 点赞 838 浏览 1583 个字
摘要 :

Seata是一款分布式事务处理应用的框架,不少开发者心中都有一个疑问:Seata的AT模式会不会出现脏读呢?答案是肯定的,不过它出现的脏读情况和传统意义上的脏读有所不同。……

Seata一款分布式事务处理应用的框架,不少开发者心中都有一个疑问:Seata的AT模式会不会出现脏读呢?答案是肯定的,不过它出现的脏读情况和传统意义上的脏读有所不同。传统脏读指的是在MySQL本地事务场景下,一个事务读取到了其他未提交事务的数据。而Seata的AT模式中,存在这样一种情况:一个事务可能读取到其他分支事务(也是本地事务)已提交,但后续可能因全局事务回滚而撤销的数据。这听起来有些绕,下面详细讲解,看完后大家就能理解了。

要想深入理解这个问题,首先得清楚Seata的AT模式的工作原理。AT模式的核心机制是两阶段提交:

  • 第一阶段:本地事务会立即提交,同时释放本地锁,这使得数据对其他事务可见。
  • 第二阶段:全局事务会依据协调结果来决定最终是提交还是回滚,这个过程借助undo log来进行补偿操作。

了解了工作原理后,我们来设想一个场景。假设有三个模块,分别是交易模块、订单模块和库存模块。在一次下单过程中,为确保数据的一致性,代码可能会像下面这样编写:

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开启了一个分布式事务。在这个事务中,会先调用库存服务进行库存扣减,然后再调用订单服务创建订单。整个大致的流程是这样的:Seata的AT模式会引发脏读吗?如何解决?

  1. 在交易模块(Trade)中,首先创建全局事务。
  2. 库存模块(Inventory)介入:
    • 2.1注册分支事务。
    • 2.2进行库存扣减操作,并记录undo log 。这里要注意,库存模块在数据库上的操作是基于数据库的本地事务进行的。之所以借助本地事务,是为了保障undo log(Seata使用的undo log和MySQL中MVCC的undo log不是同一个概念)和库存扣减操作的原子性。而且,这一步执行完成后,数据库的本地事务会提交。
  3. 订单模块(Order)参与:
    • 3.1注册分支事务。
    • 3.2创建订单,并记录undo log 。

这里关键的一点是,当库存模块完成扣减操作,数据库的本地事务提交后,不管处于何种事务隔离级别,其他事务都能查询到提交后的新值。想象一下,如果库存扣减成功,但在创建订单时失败了,此时整个分布式事务需要回滚,会依据库存库中的undo log进行回滚操作。那么在库存模块提交后、全局事务回滚前,如果有其他事务来查询库存数据,就会读到一个本该回滚的值。这就是Seata的AT模式下出现的脏读情况,它发生在全局事务的过程中,其他事务读到了全局事务尚未最终确定提交(后续可能会回滚)的数据。

既然AT模式存在这样的脏读问题,那有没有办法避免呢?确实有一个办法,就是在查询时使用@GlobalTransactional + select * ... for update 。不过这个方法比较笨拙,它虽然能解决脏读问题,但在实际应用中会带来一些弊端。因为事务已经提交,要避免其他事务读取数据比较困难,即便实现了,也会极大地降低系统的可用性。所以,如果项目中对脏读的容忍度为零,不接受这种情况,那就不建议使用AT模式,可以考虑选择其他事务方案,例如TCC模式。

微信扫一扫

支付宝扫一扫

版权: 转载请注明出处:https://www.zuozi.net/10483.html

管理员

相关推荐
2025-08-06

文章目录 一、Reader 接口概述 1.1 什么是 Reader 接口? 1.2 Reader 与 InputStream 的区别 1.3 …

988
2025-08-06

文章目录 一、事件溯源 (一)核心概念 (二)Kafka与Golang的优势 (三)完整代码实现 二、命令…

465
2025-08-06

文章目录 一、证明GC期间执行native函数的线程仍在运行 二、native线程操作Java对象的影响及处理方…

348
2025-08-06

文章目录 一、事务基础概念 二、MyBatis事务管理机制 (一)JDBC原生事务管理(JdbcTransaction)…

456
2025-08-06

文章目录 一、SnowFlake算法核心原理 二、SnowFlake算法工作流程详解 三、SnowFlake算法的Java代码…

517
2025-08-06

文章目录 一、本地Jar包的加载操作 二、本地Class的加载方法 三、远程Jar包的加载方式 你知道Groo…

832
发表评论
暂无评论

还没有评论呢,快来抢沙发~

助力内容变现

将您的收入提升到一个新的水平

点击联系客服

在线时间:08:00-23:00

客服QQ

122325244

客服电话

400-888-8888

客服邮箱

122325244@qq.com

扫描二维码

关注微信客服号