微服务分布式事务实战:Seata AT模式集成Spring Boot全流程指南

后端开发中,微服务架构将单体系统拆分为独立部署的服务单元,每个服务拥有独立数据库。跨服务的数据一致性需要分布式事务保障。Seata是阿里巴巴开源的分布式事务解决方案,AT模式通过SQL解析和undo_log自动生成补偿逻辑,对业务代码侵入最小。本文以Spring Boot集成Seata AT模式为例,拆解配置流程和事务验证方法。

Seata AT模式两阶段提交原理

AT模式(Auto Transaction)分两阶段执行。第一阶段:拦截业务SQL,生成执行前快照和执行后快照存入undo_log表,本地事务提交。第二阶段:全局事务决议提交时异步删除undo_log;决议回滚时根据undo_log生成反向SQL补偿。

AT模式核心组件:

  • TC(Transaction Coordinator):事务协调器,维护全局事务和分支事务状态,驱动提交或回滚
  • TM(Transaction Manager):事务管理器,定义全局事务边界,开启/提交/回滚全局事务
  • RM(Resource Manager):资源管理器,管理分支事务上的资源,向TC注册分支事务

与XA模式不同,AT模式第一阶段即提交本地事务,释放数据库锁,不会长时间占用连接资源。代价是存在短暂的数据不一致窗口,需要通过全局锁隔离并发写操作。

Spring Boot集成Seata配置实战

Seata Server(TC)独立部署,微服务通过SDK注册为TM和RM。服务治理层面,Seata支持Nacos、Eureka、Consul作为注册中心。

Seata Server Docker部署:

version: '3'
services:
  seata-server:
    image: seataio/seata-server:2.0.0
    ports:
      - "8091:8091"
      - "7091:7091"
    environment:
      - SEATA_PORT=8091
      - STORE_MODE=db
      - SEATA_IP=192.168.1.100
    volumes:
      - ./seata-config/application.yml:/seata-server/resources/application.yml

Spring Boot微服务端依赖配置:

<!-- pom.xml -->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-seata</artifactId>
    <version>2023.0.1.0</version>
</dependency>
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid-spring-boot-3-starter</artifactId>
    <version>1.2.22</version>
</dependency>

application.yml配置:

seata:
  enabled: true
  application-id: order-service
  tx-service-group: default_tx_group
  service:
    vgroup-mapping:
      default_tx_group: default
    grouplist:
      default: 127.0.0.1:8091
  registry:
    type: nacos
    nacos:
      server-addr: 127.0.0.1:8848
      namespace: seata
  config:
    type: nacos
    nacos:
      server-addr: 127.0.0.1:8848
      namespace: seata
  datasource:
    proxy: true

每个参与分布式事务的数据库需创建undo_log表:

CREATE TABLE `undo_log` (
  `branch_id` bigint NOT NULL COMMENT 'branch transaction id',
  `xid` varchar(128) NOT NULL COMMENT 'global transaction id',
  `context` varchar(128) NOT NULL COMMENT 'undo_log context',
  `rollback_info` longblob NOT NULL COMMENT 'rollback info',
  `log_status` int NOT NULL COMMENT '0:normal status,1:defense status',
  `log_created` datetime(6) NOT NULL COMMENT 'create datetime',
  `log_modified` datetime(6) NOT NULL COMMENT 'modify datetime',
  UNIQUE KEY `ux_undo_log` (`xid`,`branch_id`)
) ENGINE=InnoDB COMMENT='AT transaction mode undo table';

分布式事务场景演示与回滚验证

以电商下单场景为例:订单服务创建订单,库存服务扣减库存,账户服务扣减余额。三个操作要么全部成功,要么全部回滚。

订单服务TM入口:

@Service
public class OrderService {

    @Autowired
    private OrderMapper orderMapper;
    @Autowired
    private StorageFeignClient storageClient;
    @Autowired
    private AccountFeignClient accountClient;

    @GlobalTransactional(name = "createOrder", rollbackFor = Exception.class)
    public void createOrder(OrderDTO dto) {
        // 1. 创建订单
        Order order = new Order();
        order.setUserId(dto.getUserId());
        order.setProductId(dto.getProductId());
        order.setCount(dto.getCount());
        order.setMoney(dto.getMoney());
        order.setStatus(0);
        orderMapper.insert(order);

        // 2. 远程调用扣减库存
        Result storageResult = storageClient.decrease(dto.getProductId(), dto.getCount());
        if (!storageResult.isSuccess()) {
            throw new RuntimeException("库存扣减失败: " + storageResult.getMessage());
        }

        // 3. 远程调用扣减余额
        Result accountResult = accountClient.decrease(dto.getUserId(), dto.getMoney());
        if (!accountResult.isSuccess()) {
            throw new RuntimeException("余额扣减失败: " + accountResult.getMessage());
        }

        // 4. 修改订单状态
        orderMapper.updateStatus(order.getId(), 1);
    }
}

@GlobalTransactional注解标记全局事务边界。库存服务和账户服务作为RM,其本地事务自动注册为分支事务,无需额外注解。

库存服务分支事务:

@Service
public class StorageService {

    @Autowired
    private StorageMapper storageMapper;

    @Transactional(rollbackFor = Exception.class)
    public void decrease(Long productId, Integer count) {
        Storage storage = storageMapper.selectByProductId(productId);
        if (storage == null || storage.getResidue() < count) {
            throw new RuntimeException("库存不足");
        }
        storageMapper.decrease(productId, count);
    }
}

回滚验证方法:在账户服务扣减余额后手动抛出异常,观察订单和库存是否回滚。检查各服务数据库的undo_log表,回滚后记录应被清理。

生产环境Seata集群部署与调优

生产环境Seata Server需集群部署保证高可用。高并发设计下需关注全局锁竞争和事务超时配置。

集群部署要点:

  • 多实例Seata Server通过Nacos注册,client端自动负载均衡
  • DB存储模式使用独立MySQL实例,配置主从复制
  • global_table定期清理已完成事务记录,避免表膨胀
  • 设置合理的transaction.info.timeout(默认60秒),超时自动回滚

消息中间件配合Seata实现最终一致性方案。对于允许短暂不一致的场景,用RocketMQ事务消息替代AT模式,降低全局锁竞争。API接口规范上,建议对外暴露的接口返回统一Result对象包含事务XID,便于链路追踪和问题定位。

seata:
  client:
    rm:
      lock:
        retry-interval: 10
        retry-times: 30
        retry-policy-branch-rollback-on-conflict: true
    tm:
      commit-retry-count: 3
      rollback-retry-count: 3
      default-global-transaction-timeout: 60000

retry-policy-branch-rollback-on-conflict=true表示分支事务获取全局锁冲突时,直接触发回滚而非无限重试。该配置在高并发写场景下能避免死锁,代价是少量事务需要业务层重试。业务中台建设时,分布式事务方案的选择需根据一致性要求、吞吐量和复杂度综合权衡,AT模式适合强一致性要求的金融交易场景,TCC和Saga模式适合长事务和最终一致性场景。

原创文章,作者:小编,如若转载,请注明出处:https://www.yunthe.com/wei-fu-wu-fen-bu-shi-shi-wu-shi-zhan-seataat-mo-shi-ji/

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

相关推荐