Spring Boot微服务架构下分布式事务的Seata AT模式实战

微服务架构拆分后,原本在单库中靠数据库事务保证的数据一致性,变成了跨服务调用链路上的分布式事务问题。Spring Boot框架下,Seata的AT模式是侵入性最低的解决方案,对业务代码几乎零改造即可实现全局事务管理。本文从原理到落地,完整演示Seata AT模式在Spring Boot微服务中的集成方案。

分布式事务问题场景与方案对比

经典场景:电商下单流程中,订单服务创建订单、库存服务扣减库存、账户服务扣减余额,三个操作必须要么全部成功,要么全部回滚。微服务架构下每个服务独立数据库,本地事务无法跨库生效。

常见分布式事务方案对比:

2PC(XA协议):强一致性,但同步阻塞性能差,数据库需支持XA,实际生产中使用较少。

TCC(Try-Confirm-Cancel):性能好,但每个分支事务需要实现三个接口,开发成本高,侵入性强。

Saga:长事务场景友好,但只有补偿没有回滚,最终一致性,适合业务流程编排。

Seata AT模式:自动生成回滚SQL,对业务代码侵入性极低,只需一个@GlobalTransactional注解。适合大多数OLTP场景。

Seata Server搭建与配置

Seata AT模式需要一个独立的事务协调器(TC)。部署步骤:

1. 下载Seata Server:

wget https://github.com/seata/seata/releases/download/v2.2.0/seata-server-2.2.0.tar.gz
tar -xzf seata-server-2.2.0.tar.gz
cd seata-server-2.2.0

2. 配置注册中心(Nacos)和数据存储(MySQL):

# conf/application.yml
server:
  port: 7091

seata:
  registry:
    type: nacos
    nacos:
      server-addr: 127.0.0.1:8848
      namespace: seata
      group: DEFAULT_GROUP
  store:
    mode: db
    db:
      datasource: druid
      db-type: mysql
      url: jdbc:mysql://127.0.0.1:3306/seata?rewriteBatchedStatements=true
      user: root
      password: your_password

3. 初始化Seata元数据表(global_table、branch_table、lock_table),建表SQL在源码的script/server/db/目录下。

4. 启动Server:bin/seata-server.sh

Spring Boot微服务集成Seata AT模式

每个参与分布式事务的微服务都需要集成Seata客户端。以订单服务为例:

1. 添加Maven依赖:

<dependency>
  <groupId>io.seata</groupId>
  <artifactId>seata-spring-boot-starter</artifactId>
  <version>2.2.0</version>
</dependency>

2. 配置Seata客户端:

# application.yml
seata:
  enabled: true
  application-id: order-service
  tx-service-group: my-tx-group
  service:
    vgroup-mapping:
      my-tx-group: default
  registry:
    type: nacos
    nacos:
      server-addr: 127.0.0.1:8848
      namespace: seata

3. 每个微服务的数据库中添加undo_log表(AT模式的核心,存储回滚数据):

CREATE TABLE undo_log (
  id BIGINT PRIMARY KEY AUTO_INCREMENT,
  branch_id BIGINT NOT NULL,
  xid VARCHAR(100) 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;

业务代码中的全局事务控制

订单服务的业务入口加上@GlobalTransactional注解:

@Service
public class OrderService {

    @Autowired
    private OrderMapper orderMapper;
    @Autowired
    private InventoryClient inventoryClient;
    @Autowired
    private AccountClient accountClient;

    @GlobalTransactional(name = "create-order", rollbackFor = Exception.class)
    public Order createOrder(OrderDTO dto) {
        // 1. 创建订单
        Order order = new Order();
        order.setUserId(dto.getUserId());
        order.setProductId(dto.getProductId());
        order.setAmount(dto.getAmount());
        order.setStatus("CREATED");
        orderMapper.insert(order);

        // 2. 远程调用库存服务扣减库存
        inventoryClient.deduct(dto.getProductId(), dto.getQuantity());

        // 3. 远程调用账户服务扣减余额
        accountClient.debit(dto.getUserId(), dto.getAmount());

        // 4. 更新订单状态
        order.setStatus("PAID");
        orderMapper.updateById(order);

        return order;
    }
}

AT模式的工作流程:进入方法时Seata TC生成全局XID → 每个分支事务执行前拦截SQL,保存前镜像(before-image)到undo_log → 执行业务SQL → 保存后镜像(after-image)到undo_log → 全局提交时异步删除undo_log → 全局回滚时根据undo_log中的镜像数据自动生成反向SQL执行补偿。

消息中间件与Seata的协作策略

当微服务间通过消息中间件(如RocketMQ)异步通信时,Seata AT模式无法直接管控异步消费者的分支事务。处理策略:

方案一:在消息生产者端使用本地消息表+Seata全局事务,确保消息发送和本地操作的一致性。消费者端独立处理,失败时重试。

方案二:使用Seata的Saga模式编排包含异步步骤的长流程事务,通过状态机控制每一步的补偿逻辑。

方案三:核心链路(下单、支付)走同步调用+Seata AT,非核心链路(通知、日志)走消息中间件+最终一致性。

服务治理:Seata集群高可用与监控

生产环境Seata TC必须集群部署。推荐至少3个节点,通过Nacos注册中心实现服务发现。客户端配置多个TC节点的cluster地址,任一节点宕机自动切换。

监控指标通过Micrometer接入Prometheus:全局事务创建数、提交成功率、回滚率、分支事务平均耗时。回滚率持续超过5%需要排查业务代码或网络问题。

常见踩坑点:undo_log表缺失导致AT模式静默退化为本地事务;数据库字段类型与Java实体类型不匹配导致镜像序列化失败;Nacos命名空间配置不一致导致TC不可达;Seata版本与Spring Boot版本不兼容(2.2.x对应Spring Boot 3.x)。

原创文章,作者:小编,如若转载,请注明出处:https://www.yunthe.com/springboot-wei-fu-wu-jia-gou-xia-fen-bu-shi-shi-wu-de/

(0)
小编小编
上一篇 13小时前
下一篇 13小时前

相关推荐