Spring Boot微服务分布式事务实战:Seata AT模式从配置到生产调优

分布式事务问题的典型场景

微服务拆分后,一个业务操作可能跨多个服务,每个服务有独立的数据库。下单场景涉及订单服务扣减库存、账户服务扣减余额、积分服务增加积分——三个操作必须全部成功或全部回滚。本地事务无法覆盖跨库操作,这就是分布式事务要解决的问题。

Seata的AT模式是对业务代码侵入最小的方案,只需要一个@GlobalTransactional注解。其原理是在SQL执行前后自动生成回滚日志(undo log),事务失败时自动根据undo log反向补偿。

Seata Server部署与Nacos注册中心集成

Seata Server是事务协调器(TC),负责管理全局事务的提交和回滚。生产环境推荐使用Nacos作为注册中心和配置中心。

# docker部署Seata Server
version: '3'
services:
  seata-server:
    image: seataio/seata-server:2.2.0
    container_name: seata-server
    ports:
      - "8091:8091"
      - "7091:7091"
    environment:
      - SEATA_IP=192.168.1.100
      - SEATA_PORT=8091
    volumes:
      - ./seata-config:/seata-server/resources
    restart: always

# seata-config/application.yml 关键配置
seata:
  config:
    type: nacos
    nacos:
      server-addr: 192.168.1.10:8848
      namespace: seata
      group: SEATA_GROUP
  registry:
    type: nacos
    nacos:
      application: seata-server
      server-addr: 192.168.1.10:8848
      namespace: seata
      group: SEATA_GROUP
  store:
    mode: db
    db:
      datasource: druid
      driver-class-name: com.mysql.cj.jdbc.Driver
      url: jdbc:mysql://192.168.1.10:3306/seata?rewriteBatchedStatements=true
      user: seata
      password: seata_pwd
      min-conn: 5
      max-conn: 30

微服务客户端集成:数据源代理与undo log表

每个参与分布式事务的微服务需要配置Seata数据源代理,并在业务库中创建undo_log表。

<!-- pom.xml 依赖 -->
<dependency>
  <groupId>io.seata</groupId>
  <artifactId>seata-spring-boot-starter</artifactId>
  <version>2.2.0</version>
</dependency>
<dependency>
  <groupId>com.alibaba.cloud</groupId>
  <artifactId>spring-cloud-starter-alibaba-seata</artifactId>
  <version>2023.0.1.0</version>
</dependency>
-- 每个业务库都需要创建undo_log表
CREATE TABLE IF NOT EXISTS `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(11)      NOT NULL COMMENT '0:normal, 1:defensed',
  `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 DEFAULT CHARSET=utf8mb4 COMMENT='AT transaction undo log';

业务代码实现:@GlobalTransactional注解与Feign调用

在业务入口方法上添加@GlobalTransactional注解,Seata通过拦截SQL自动管理事务上下文。

@Service
public class OrderService {

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

    @GlobalTransactional(name = "create-order", rollbackFor = Exception.class)
    public OrderResult createOrder(OrderRequest request) {
        // 1. 创建订单(本地事务,Seata自动代理)
        Order order = new Order();
        order.setUserId(request.getUserId());
        order.setProductId(request.getProductId());
        order.setQuantity(request.getQuantity());
        order.setAmount(request.getAmount());
        order.setStatus("CREATED");
        orderMapper.insert(order);

        // 2. 扣减库存(远程调用,XID自动传播)
        inventoryClient.deduct(request.getProductId(), request.getQuantity());

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

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

        return OrderResult.success(order.getId());
    }
}

// Feign客户端——XID通过请求头自动传播
@FeignClient(name = "account-service", fallback = AccountFallback.class)
public interface AccountClient {
    @PostMapping("/account/debit")
    Result debit(@RequestParam("userId") Long userId,
                 @RequestParam("amount") BigDecimal amount);
}

XID(全局事务ID)通过HTTP Header在服务间自动传播,这是Seata Spring Cloud集成的核心机制。Feign拦截器自动将当前XID写入请求头,对端服务自动解析并绑定到当前分支事务。

生产环境调优:超时、重试与全局锁

AT模式的核心风险是全局锁。一阶段本地事务提交后,Seata会对修改的数据加全局锁,直到全局事务提交或回滚才释放。如果全局事务耗时过长,全局锁会阻塞其他事务。

# 超时与重试配置
seata:
  client:
    rm:
      async-commit-buffer-limit: 10000
      report-retry-count: 5
      lock:
        retry-interval: 10    # 全局锁重试间隔(ms)
        retry-times: 30       # 全局锁重试次数
    tm:
      commit-retry-count: 3
      rollback-retry-count: 3
      default-global-transaction-timeout: 60000  # 全局事务超时60秒

全局事务超时时间需要根据业务场景设置。跨三个服务的订单创建通常5秒内完成,但涉及外部支付网关时可能需要30秒以上。超时后Seata自动回滚,避免全局锁长期占用。

undo log的清理同样重要。已完成的全局事务的undo log默认保留7天,高频业务场景下undo log表可能积累大量数据,影响回滚性能。配置定时清理任务:

@Scheduled(cron = "0 0 3 * * ?")
public void cleanUndoLog() {
    int deleted = undoLogMapper.cleanExpiredLogs(
        LocalDate.now().minusDays(7)
    );
    log.info("清理undo_log记录数: {}", deleted);
}

分布式事务没有银弹,Seata AT模式适合对一致性要求高、并发量中等的场景。超高频场景考虑TCC模式或最终一致性方案(如本地消息表+定时补偿),低频但强一致场景用AT模式最省心。

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

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

相关推荐

发表回复

登录后才能评论