第30课:分布式事务解决方案 & Seata最终一致性实战

文章目录

适配版本 :Seata 2.5.0、Spring Cloud Alibaba 2025.1.0.0、Spring Cloud 2025.1.3(Oakwood)、Spring Boot 4.0.8、Nacos Server 3.1.1、JDK 21

课程定位:微服务高阶阶段核心课,从分布式事务理论到Seata AT模式实战,构建跨服务数据一致性保障能力

一、开篇:第29课留下的"一致性缺口"

第29课我们完成了微服务异步调用、线程池优化和事件驱动开发。通过@Async和Spring事件,我们将非核心流程从主流程中剥离,大幅提升了接口响应速度。但异步也带来了一个新的问题:数据一致性。

考虑一个场景:订单服务创建订单后,异步发送消息通知库存服务扣减库存。如果订单创建成功,但异步消息发送失败,库存没有被扣减,就会出现"订单已创建但库存未扣减"的数据不一致。更严重的是,@Async方法的事务与主方法的事务是独立的------主方法的事务回滚了,异步方法的事务可能已经提交,数据就"飘"了。

在第16课我们讨论过Feign调用的一致性,但当时的方案(本地消息表、Seata AT模式简介)只是浅尝辄止。现在必须正面回答一个核心问题:当一次业务操作需要跨多个服务、多个数据库时,如何保证数据要么全部成功,要么全部回滚?

这就是分布式事务 要解决的问题。Seata是Spring Cloud Alibaba生态中分布式事务的事实标准方案,它提供了AT、TCC、SAGA、XA四种模式,其中AT模式以零侵入 著称------只需要一个@GlobalTransactional注解,就能将本地事务升级为分布式事务。Spring Cloud Alibaba 2025.1.0.0正式适配了Seata 2.5.0,并新增了对WebFlux的支持。

本课将从CAP/BASE理论讲起,深入Seata的三组件架构(TC/TM/RM)和AT模式的两阶段提交原理,完成Seata Server部署和订单扣库存的完整实战,最后给出生产环境的性能调优和踩坑方案。

二、分布式事务理论基础

2.1 CAP理论:分布式系统的"不可能三角"

CAP理论指出,一个分布式系统无法同时满足以下三个特性:

特性 含义 取舍
Consistency(一致性) 所有节点在同一时刻看到相同的数据 与A冲突
Availability(可用性) 每个请求都能在有限时间内得到响应 与C冲突
Partition Tolerance(分区容错性) 系统在节点间通信中断时仍能继续运行 分布式系统必须满足

核心结论 :由于网络分区(P)在分布式系统中不可避免 ,系统实际上只能在一致性(CP) 和可用性(AP) 之间二选一。分布式事务框架的选择本质上是在这个权衡中做出决策。

  • CP型方案(如XA、2PC):强一致性优先,但协调者宕机时参与者会阻塞,可用性降低
  • AP型方案(如AT、TCC、SAGA、本地消息表):最终一致性优先,性能更好,但存在短暂的数据不一致窗口

2.2 BASE理论:AP路线的落地指南

BASE理论是对CAP中AP方案的延伸,包含三个核心要素:

要素 含义 在微服务中的体现
Basically Available(基本可用) 允许损失部分可用性,保证核心功能可用 大促期间降级非核心功能
Soft State(软状态) 允许系统存在中间状态,不影响整体可用性 订单"支付中"状态
Eventually Consistent(最终一致) 经过一段时间后,所有节点数据最终一致 异步补偿、定期对账

BASE理论的核心思想 :放弃强一致性,通过补偿机制在事后达成一致。Seata的AT模式、TCC模式、SAGA模式都遵循BASE理论,属于最终一致性方案。XA模式则属于CP路线。

三、Seata架构深度剖析

3.1 三大核心组件:TC、TM、RM

Seata的全称是 Simple Extensible Autonomous Transaction Architecture,它通过三个核心组件协同工作:

组件 全称 职责 部署位置
TC Transaction Coordinator 事务协调者,维护全局事务和分支事务的状态,驱动全局提交或回滚 独立部署的Seata Server
TM Transaction Manager 事务管理器,定义全局事务的范围,发起全局提交或回滚 业务应用(发起方)
RM Resource Manager 资源管理器,管理分支事务处理的资源,向TC注册分支事务 业务应用(参与方)

一次全局事务的完整生命周期:

复制代码
TM 向 TC 申请开启全局事务
    │  TC 生成全局唯一 XID,返回给 TM
    ▼
TM 将 XID 绑定到当前线程上下文
    │  通过 Feign / RPC 调用时将 XID 透传到下游服务
    ▼
RM 拦截业务 SQL,向 TC 注册分支事务
    │  获取 Branch ID
    │  执行 SQL,记录 undo_log,提交本地事务
    ▼
所有分支事务执行完毕,TM 向 TC 发起全局提交 / 回滚
    │
    ▼
TC 驱动所有 RM 完成 Phase 2 操作
    │  提交 → 异步删除 undo_log
    │  回滚 → 根据 undo_log 反向补偿

3.2 XID的传递机制

XID是全局事务的唯一标识,格式为{ip}:{port}:{transactionId},例如192.168.1.100:8091:1234567890。XID的传递是链路串联的核心:

传递场景 传递方式 是否需要手动处理
Spring Cloud / OpenFeign 通过HTTP Header自动透传 ✅ 自动
Dubbo 通过RPC Context自动透传 ✅ 自动
消息队列(RocketMQ/Kafka) 需手动在消息体中绑定XID ⚠️ 手动
自定义线程池 需手动RootContext.bind(xid) ⚠️ 手动
Spring Cloud Gateway 需添加XID到白名单,避免被过滤 ⚠️ 手动

Spring Cloud Alibaba 2025.1.0.0新增了对WebFlux的支持,这意味着Gateway(基于WebFlux)也能正确透传XID,之前版本中Gateway链路断裂的问题得到了解决。

四、AT模式深度剖析:两阶段提交的"零侵入"实现

4.1 AT模式的整体机制

AT(Automatic Transaction)模式是Seata默认 的分布式事务模式,也是Spring Cloud Alibaba生态中使用最广的方案。它的核心创新在于:通过数据源代理自动拦截SQL,在不修改业务代码的前提下实现分布式事务。

AT模式采用改进的两阶段提交(2PC) 模型:

阶段一(Phase 1):执行并记录

复制代码
① 拦截业务 SQL,解析 SQL 语义(SQL类型、表名、条件)
② 查询数据前镜像(Before Image)------ SELECT ... FOR UPDATE
③ 执行业务 SQL(UPDATE / INSERT / DELETE)
④ 查询数据后镜像(After Image)
⑤ 保存 undo_log 回滚日志(记录前后镜像)
⑥ 提交本地事务(立即释放本地锁和连接资源)
⑦ 向 TC 汇报执行结果

关键设计 :业务数据和undo_log在同一个本地事务中提交,保证了"要么都成功,要么都失败"。

阶段二(Phase 2):提交或回滚

复制代码
成功提交:
  TC 异步通知 RM 删除 undo_log(无需同步等待,性能极高)

失败回滚:
  TC 通知 RM 根据 undo_log 中的前镜像恢复数据
  回滚完成后删除 undo_log

4.2 数据源代理技术

AT模式的"零侵入"依赖于数据源代理(DataSourceProxy) 。Seata通过代理真实数据源,在SQL执行层插入事务逻辑:

代理层级 代理对象 拦截的调用
DataSourceProxy 数据源代理 getConnection()
ConnectionProxy 连接代理 prepareStatement()、commit()
StatementProxy 语句代理 executeXXX()

自动注册流程:

复制代码
业务代码执行 SQL → mapper.insert()
    │
    ▼
DataSourceProxy 拦截 → 检查 RootContext 中是否有 XID
    │
    ├─ 有 XID → 向 TC 注册分支事务,获取 Branch ID
    │
    └─ 无 XID → 普通本地事务,直接执行
    │
    ▼
查询前镜像 → 执行 SQL → 查询后镜像 → 保存 undo_log → 提交本地事务

4.3 全局锁与隔离性

AT模式的默认全局隔离级别是读未提交(Read Uncommitted) 。这意味着在全局事务提交之前,其他事务可能看到未提交的数据修改。

为什么不做读已提交? 因为AT模式Phase 1就提交了本地事务,如果要求全局读已提交,所有读操作都需要加全局锁,性能会急剧下降。

需要读已提交时的解决方案 :在查询SQL上使用SELECT ... FOR UPDATE。Seata通过SelectForUpdateExecutor代理该语句,在获取数据库本地锁后,再检查全局锁是否存在。如果全局锁被其他事务持有,则回滚本地事务并重试,直到获取全局锁。

全局锁的工作机制:

操作 全局锁行为
写操作 Phase 1 注册分支事务时获取全局锁;Phase 2 完成后释放
读操作(SELECT) 默认不加全局锁,可能读到未提交数据
读操作(SELECT FOR UPDATE) 代理后先检查全局锁,若存在则等待或重试

五、Seata Server部署实战

5.1 Seata 2.5.0新特性

Seata 2.5.0于2025年7月21日发布,关键变更包括:

特性 说明
强制账户初始化 禁止使用默认凭证,提升安全性
HTTP/2支持 Seata Server支持HTTP/2协议,通信性能提升
OceanBase Oracle支持 新增对OceanBase Oracle模式的支持
Tomcat替换为Netty-HTTP 服务端Web容器从Tomcat切换为Netty,降低资源消耗

5.2 存储模式选择

Seata Server支持三种事务日志存储模式:

模式 说明 适用场景
file 文件存储,事务日志写入本地文件 开发/测试环境
db 数据库存储,事务日志持久化到MySQL等数据库 生产环境推荐
redis Redis存储,事务日志持久化到Redis 高性能场景

生产环境必须使用db或redis模式,file模式在服务重启后事务日志会丢失,导致无法恢复未完成的事务。

5.3 数据库初始化

使用db模式需要先创建Seata的数据库表:

sql 复制代码
-- 全局事务表
CREATE TABLE global_table (
    xid VARCHAR(128) NOT NULL,
    transaction_id BIGINT,
    status TINYINT,
    application_id VARCHAR(32),
    transaction_service_group VARCHAR(32),
    transaction_name VARCHAR(128),
    timeout INT,
    begin_time BIGINT,
    application_data VARCHAR(2000),
    gmt_create DATETIME,
    gmt_modified DATETIME,
    PRIMARY KEY (xid),
    KEY idx_gmt_modified_status (gmt_modified, status),
    KEY idx_transaction_id (transaction_id)
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4;

-- 分支事务表
CREATE TABLE branch_table (
    branch_id BIGINT NOT NULL,
    xid VARCHAR(128) NOT NULL,
    transaction_id BIGINT,
    resource_group_id VARCHAR(32),
    resource_id VARCHAR(256),
    branch_type VARCHAR(8),
    status TINYINT,
    client_id VARCHAR(64),
    application_data VARCHAR(2000),
    gmt_create DATETIME(6),
    gmt_modified DATETIME(6),
    PRIMARY KEY (branch_id),
    KEY idx_xid (xid)
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4;

-- 全局锁表
CREATE TABLE lock_table (
    row_key VARCHAR(128) NOT NULL,
    xid VARCHAR(128),
    transaction_id BIGINT,
    branch_id BIGINT,
    resource_id VARCHAR(256),
    table_name VARCHAR(32),
    pk VARCHAR(36),
    gmt_create DATETIME,
    gmt_modified DATETIME,
    PRIMARY KEY (row_key),
    KEY idx_branch_id (branch_id)
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4;

业务库需要额外创建undo_log表(每个参与分布式事务的业务数据库都需要):

sql 复制代码
CREATE TABLE undo_log (
    branch_id BIGINT NOT NULL,
    xid VARCHAR(128) NOT NULL,
    context VARCHAR(128) NOT NULL,
    rollback_info LONGBLOB NOT NULL,
    log_status INT NOT NULL,
    log_created DATETIME NOT NULL,
    log_modified DATETIME NOT NULL,
    UNIQUE KEY ux_undo_log (xid, branch_id)
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4;

5.4 Seata Server配置

编辑seata-server/conf/application.yml:

yaml 复制代码
server:
  port: 7091    # 控制台端口

seata:
  config:
    type: nacos
    nacos:
      server-addr: 127.0.0.1:8848
      namespace: seata
      group: SEATA_GROUP
      data-id: seataServer.properties

  registry:
    type: nacos
    nacos:
      application: seata-server
      server-addr: 127.0.0.1:8848
      namespace: seata
      group: SEATA_GROUP

  store:
    mode: db
    db:
      datasource: druid
      db-type: mysql
      driver-class-name: com.mysql.cj.jdbc.Driver
      url: jdbc:mysql://127.0.0.1:3306/seata?useSSL=false&serverTimezone=UTC
      user: seata
      password: Seata@2026!
      min-conn: 5
      max-conn: 100

  security:
    secret-key: SeataSecretKey0c382ef121d778043159209298fd40bf3850a017
    token-validity-in-seconds: 1800

Seata 2.5.0的安全变更 :2.5.0强制要求初始化账户并禁用默认凭证。必须在application.yml中配置security.secret-key,否则启动会失败。

5.5 启动Seata Server

bash 复制代码
# Linux/macOS
sh bin/seata-server.sh -p 8091 -m db

# Windows
bin\seata-server.bat -p 8091 -m db

启动后访问http://localhost:7091,使用初始化时设置的账户登录控制台。

六、AT模式完整实战:订单扣库存

6.1 依赖配置

在service-order、service-product(库存服务)的POM中添加Seata依赖:

xml 复制代码
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-seata</artifactId>
</dependency>

版本由Spring Cloud Alibaba BOM(2025.1.0.0)统一管理,对应Seata 2.5.0。

6.2 应用配置

在两个服务的application.yml中添加:

yaml 复制代码
seata:
  enabled: true
  application-id: ${spring.application.name}
  tx-service-group: my_tx_group
  service:
    vgroup-mapping:
      my_tx_group: default
    grouplist:
      default: 127.0.0.1:8091
  registry:
    type: nacos
    nacos:
      server-addr: 127.0.0.1:8848
      namespace: seata
      group: SEATA_GROUP
      application: seata-server
  config:
    type: nacos
    nacos:
      server-addr: 127.0.0.1:8848
      namespace: seata
      group: SEATA_GROUP
      data-id: seataServer.properties
  enable-auto-data-source-proxy: true    # 自动代理数据源
  data-source-proxy-mode: AT              # 使用AT模式

enable-auto-data-source-proxy: true 是AT模式的核心配置。开启后,Seata会自动将Spring管理的DataSource包装为DataSourceProxy,业务代码无需任何修改。

6.3 订单服务:发起全局事务

java 复制代码
@Service
@Slf4j
public class OrderService {

    @Autowired
    private OrderMapper orderMapper;
    @Autowired
    private ProductFeignClient productFeignClient;

    @GlobalTransactional(name = "create-order", timeoutMills = 30000)
    public OrderVO createOrder(OrderCreateRequest request) {
        log.info("开始创建订单: productId={}, quantity={}",
                request.getProductId(), request.getQuantity());

        // 1. 本地事务:创建订单
        Order order = new Order();
        order.setOrderNo(IdUtils.generateOrderNo());
        order.setUserId(request.getUserId());
        order.setProductId(request.getProductId());
        order.setQuantity(request.getQuantity());
        order.setStatus(OrderStatus.CREATED);
        orderMapper.insert(order);

        // 2. 远程调用:扣减库存(通过Feign,XID自动透传)
        Result<Void> stockResult = productFeignClient.decreaseStock(
                new StockDecreaseRequest(request.getProductId(), request.getQuantity()));

        if (!stockResult.isSuccess()) {
            throw new BusinessException("库存不足");
        }

        // 3. 更新订单状态
        orderMapper.updateStatus(order.getOrderNo(), OrderStatus.CONFIRMED);

        log.info("订单创建成功: orderNo={}", order.getOrderNo());
        return OrderVO.from(order);
    }
}

@GlobalTransactional的关键参数:

参数 含义 建议值
name 全局事务名称,用于监控和日志 业务含义明确的名称
timeoutMills 全局事务超时时间(毫秒) 30000(30秒)
rollbackFor 触发回滚的异常类型 Throwable.class

6.4 库存服务:分支事务

java 复制代码
@Service
@Slf4j
public class StockService {

    @Autowired
    private StockMapper stockMapper;

    public void decreaseStock(Long productId, Integer quantity) {
        log.info("扣减库存: productId={}, quantity={}", productId, quantity);

        // 查询当前库存
        Stock stock = stockMapper.selectByProductId(productId);
        if (stock == null || stock.getCount() < quantity) {
            throw new BusinessException("库存不足");
        }

        // 扣减库存(Seata自动拦截SQL,记录undo_log)
        int affected = stockMapper.decreaseStock(productId, quantity);
        if (affected == 0) {
            throw new BusinessException("库存扣减失败");
        }

        log.info("库存扣减成功: productId={}", productId);
    }
}

关键理解 :库存服务的decreaseStock方法不需要 添加@GlobalTransactional。Seata的数据源代理会自动拦截SQL,从RootContext中获取XID,自动注册分支事务。

6.5 验证分布式事务

场景一:正常下单(全部成功)

bash 复制代码
curl -X POST http://localhost:8082/api/order/create \
  -H "Content-Type: application/json" \
  -d '{"userId":1,"productId":100,"quantity":2}'
# 预期:订单创建成功,库存扣减成功

场景二:库存不足(全局回滚)

bash 复制代码
curl -X POST http://localhost:8082/api/order/create \
  -H "Content-Type: application/json" \
  -d '{"userId":1,"productId":999,"quantity":1000}'
# 预期:返回"库存不足",订单记录被回滚删除,库存未变化

验证回滚 :查询订单表和库存表,确认订单记录已被删除,库存数量未变化。查看业务库的undo_log表,应能看到回滚记录。

七、AT模式与其他模式的对比

7.1 四种模式全景对比

Seata支持四种分布式事务模式,各有适用场景:

维度 AT TCC SAGA XA
一致性 最终一致 最终一致 最终一致 强一致
业务侵入 零侵入 高侵入 高侵入 零侵入
隔离性 读未提交(可配置) 取决于实现 无隔离 读已提交
性能 高 最高 高 低
适用场景 通用CRUD 复杂定制化业务 长事务 强一致要求场景
实现难度 低 高 中 低
补偿方式 undo_log自动反向补偿 手写Cancel方法 状态机补偿 数据库回滚

7.2 模式选型决策

场景 推荐模式 原因
通用CRUD(订单、库存、账户) AT 零侵入,开箱即用
复杂业务(需要精细控制补偿逻辑) TCC 可自定义Try/Confirm/Cancel
长事务(涉及多个系统、长时间流程) SAGA 状态机驱动,适合编排复杂流程
强一致要求(金融核心账务) XA 唯一强一致方案
性能敏感(高并发交易) TCC 无全局锁,性能最高

选型建议 :90%的场景使用AT模式即可。AT模式在CRUD场景下性能足够、零侵入、维护成本低。只有在AT模式遇到明确的性能瓶颈或业务逻辑复杂度超出AT模式能力时,才考虑切换到TCC或SAGA。

八、生产级性能调优与踩坑方案

8.1 全局锁与本地锁的死锁问题

AT模式最常见的生产问题:Lock wait timeout exceeded异常。根本原因是全局锁(Global Lock)与本地锁(Local Lock)的加锁顺序不当,形成死锁环。

死锁典型场景:

复制代码
事务1:持有 t_order 的 RECORD LOCK,等待 Seata global_lock
事务2:持有 Seata global_lock,等待 t_order 的 RECORD LOCK

根本原因 :@Transactional(本地事务)和@GlobalTransactional(全局事务)的嵌套使用。如果Feign远程调用被包裹在Spring的@Transactional中,本地数据库连接会先开启隐式锁,然后才去获取全局锁,形成了"先拿本地锁、再等全局锁"的顺序。

解决方案:

方案一:调整本地事务传播属性。 将内部本地事务的传播级别改为Propagation.REQUIRES_NEW,让本地锁在子事务中快速释放:

java 复制代码
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void createOrderLocal(Order order) {
    orderMapper.insert(order);
}

方案二:减少事务粒度(推荐)。 不要将Feign远程调用包裹在Spring事务中:

java 复制代码
@Service
public class OrderService {

    @GlobalTransactional(name = "create-order", timeoutMills = 30000)
    public void createOrder(OrderDTO dto) {
        // 1. 本地事务单独控制(使用编程式事务或脱离大事务)
        orderMapper.insert(order);

        // 2. 远程调用(剥离出Spring事务上下文)
        productFeignClient.decreaseStock(dto.getProductId(), dto.getQuantity());
    }
}

调优效果:调整后锁等待超时异常可降低98%,RT从2.3秒降至650ms。

8.2 Feign超时与Seata事务超时的配合

Seata的全局事务超时时间(timeoutMills)和Feign的超时时间需要协调配置:

超时类型 建议值 说明
Feign连接超时 3秒 快速失败
Feign读取超时 5秒 与分支事务超时同步
Seata全局事务超时 30秒 大于所有分支超时之和

关键规则 :Feign读取超时应小于Seata全局事务超时。如果Feign超时了,Seata会触发回滚;如果Seata超时了但Feign还在等待,就会导致分支事务状态不一致。

禁用Feign重试 :Seata参与的服务必须禁用Feign重试 (Retryer.NEVER_RETRY),否则重试会导致分支事务重复注册。

8.3 空回滚与悬挂问题

空回滚:TC通知RM回滚,但RM的Phase 1根本没有执行(因网络问题未收到请求),回滚操作被"空执行"。

悬挂:空回滚发生后,Phase 1的请求才到达RM并执行成功,导致数据被修改但全局事务已经回滚,数据无法恢复。

AT模式的防护 :AT模式通过undo_log的xid + branch_id唯一约束来防止重复回滚,但对于"先回滚后执行"的悬挂场景,需要额外的防护机制(TCC模式中需要业务代码手动处理)。

生产建议 :确保undo_log表的(xid, branch_id)唯一索引存在;监控undo_log表中长期未删除的记录(可能表示悬挂事务)。

8.4 性能优化参数

参数 默认值 生产建议 说明
client.rm.report.success.enable true false 关闭成功上报,减少TC压力(失败时才上报)
client.tm.commit.retry.count 5 3 全局提交重试次数
client.tm.rollback.retry.count 5 3 全局回滚重试次数
transport.threadFactory.bossThreadSize 1 1 Netty Boss线程数
transport.threadFactory.workerThreadSize 8 CPU核数×2 Netty Worker线程数

8.5 生产环境监控指标

通过Seata控制台或Prometheus监控以下指标:

指标 含义 告警阈值
seata_transaction_total 全局事务总数 突增50%告警
seata_transaction_committed_total 已提交事务数 用于计算提交率
seata_transaction_rollback_total 已回滚事务数 回滚率>5%告警
seata_branch_transaction_total 分支事务总数 突增告警
seata_lock_conflict_total 全局锁冲突次数 持续上升告警

九、踩坑指南

坑一:undo_log表不存在导致事务失败

现象 :启动时报Table 'xxx.undo_log' doesn't exist。

原因 :业务数据库未创建undo_log表。

解决 :每个参与分布式事务的业务数据库都必须创建undo_log表(第5.3节的建表语句)。

坑二:Gateway链路中XID丢失

现象:Gateway转发后的请求,Seata的XID丢失,下游服务无法加入全局事务。

原因 :Gateway的GlobalFilter修改了请求头,覆盖了Seata注入的TX_XID头。或Gateway本身是基于WebFlux的,旧版本Seata不兼容。

解决 :确保使用Spring Cloud Alibaba 2025.1.0.0和Seata 2.5.0,已支持WebFlux。在自定义过滤器中,将TX_XID头加入白名单。

坑三:@GlobalTransactional注解不生效

现象 :添加了@GlobalTransactional,但事务没有回滚。

原因 :@GlobalTransactional方法必须由Spring代理调用 (与@Transactional相同)。如果同一个类中直接调用,注解不会生效。

解决:将全局事务方法抽取到独立的Service中,或注入自身调用。

坑四:Feign重试导致分支事务重复注册

现象:Seata日志中出现大量重复的Branch ID。

原因:Feign配置了重试,超时后重试导致分支事务被重复注册。

解决 :Seata参与的服务禁用Feign重试(Retryer.NEVER_RETRY)。

坑五:生产环境使用file存储模式

现象:Seata Server重启后,未完成的事务无法恢复。

原因:file模式下事务日志存储在本地文件,重启后可能丢失。

解决 :生产环境必须使用db或redis存储模式(第5.2节)。

坑六:AT模式读到脏数据

现象:全局事务未提交时,其他事务读到了未提交的数据。

原因 :AT模式默认的全局隔离级别是读未提交。

解决 :如果需要读已提交,使用SELECT ... FOR UPDATE语句,Seata会代理该语句检查全局锁。

坑七:Seata 2.5.0启动失败------未初始化账户

现象:Seata Server启动报错,提示账户未初始化。

原因:Seata 2.5.0强制要求初始化账户并禁用默认凭证。

解决 :在application.yml中配置security.secret-key,且所有节点保持一致。

十、课后作业

作业一:使用Docker或本地部署Seata Server 2.5.0(db存储模式),配置Nacos注册和配置中心。验证控制台可正常访问。

作业二 :为service-order和service-product添加Seata依赖和配置。在undo_log表建好后,实现@GlobalTransactional的订单创建方法。

作业三:验证正常下单和库存不足两种场景。库存不足时,确认订单记录被回滚删除,库存未变化。

作业四 :模拟Feign超时,验证Seata全局回滚。在库存服务中添加Thread.sleep(10000),Feign读取超时设为5秒,确认Feign超时后Seata触发全局回滚。

作业五(进阶) :调整本地事务传播属性为Propagation.REQUIRES_NEW,对比调整前后的锁等待超时次数和RT变化。

十一、阶段总结与下节预告

至此,微服务高阶特性 & 分布式核心能力阶段(第29-31课) 已完成前两课:

课程 核心能力 关键产出
第29课 异步调用与事件驱动 @Async、线程池调优、MDC透传、Spring事件
第30课 分布式事务与Seata AT模式、全局锁、@GlobalTransactional、性能调优

两课的核心逻辑 :第29课解决了单服务内的异步与解耦 ,第30课解决了跨服务的分布式事务一致性 。第31课将进入微服务消息驱动(RabbitMQ/RocketMQ)适配与解耦实战,内容包括消息异步解耦、可靠消息投递、消费幂等、死信队列和流量削峰。消息队列与分布式事务是互补的------Seata的AT模式适合强一致场景(如支付扣款),消息队列的最终一致性适合异步解耦场景(如订单通知)。两者结合,构成微服务数据一致性的完整方案。

🔗《最新版 SpringCloud 2025 从入门到实战》系列课程导航

去订阅

第一部分:微服务前置基础 & 新版环境搭建(第1-5课)

第二部分:注册中心核心(Nacos 最新版)(第6-9课)

第三部分:配置中心核心(Nacos配置中心)(第10-12课)

第四部分:服务通信核心(OpenFeign + LoadBalancer)(第13-16课)

第五部分:网关核心(SpringCloud Gateway 新版)(第17-20课)

第六部分:熔断、限流、降级(Sentinel 新版)(第21-24课)

第七部分:微服务监控、链路追踪、日志体系(第25-28课)

第八部分:微服务高阶特性 & 分布式核心能力(第29-31课)

第九部分:企业级完整项目实战 & 架构复盘(第32-35课)

相关推荐
donk13142 小时前
React Native for OpenHarmony 实战:三方库 react-native-circular-action-menu 的鸿蒙化适配指南
javascript·分布式·react native·react.js·wpf·harmonyos
蓝胖的四次元口袋3 小时前
RabbitMQ知识梳理(1)
分布式·rabbitmq
霸道流氓气质5 小时前
Redisson BloomFilter:分布式位图实现、误判率调优与缓存穿透三级防护的 Spring Boot 生产级实战
spring boot·分布式·缓存
流烟默6 小时前
ClickHouse 集群建表实战:从引擎选择到本地表 / 分布式表落地
分布式·clickhouse
霸道流氓气质14 小时前
Serverless 架构入门与实战:FaaS/BaaS 模型、Spring Cloud Function 适配与 AI 推理冷启动优化的 Java 全栈指南
spring cloud·架构·serverless
SL_staff20 小时前
低代码选型避坑指南:为什么‘能拖拽’不等于‘能交付’?——基于JVS八大引擎的四维交付能力评估框架
java·低代码·spring cloud
donk131421 小时前
React Native for OpenHarmony 实战:三方库 react-native-step-indicator 的鸿蒙化适配指南
分布式·react native·react.js·wpf·harmonyos
梅菲塔亚1 天前
Ceph分布式存储
分布式·ceph
acrel71 天前
Acrel-1000系列分布式光伏监控系统在湖北荆门一马光彩大市场屋顶光伏发电项目中应用
分布式·光伏并网