Seata分布式事务实战:AT模式集成Spring Boot配置指南

分布式事务问题背景与Seata架构原理

微服务架构下,单个业务操作可能跨多个独立数据库,传统本地事务无法保证数据一致性。例如电商下单场景涉及订单服务、库存服务、账户服务三个独立数据库,任一环节失败都需要全部回滚。Seata是阿里巴巴开源的分布式事务解决方案,AT(Automatic Transaction)模式通过自动生成回滚SQL实现无损补偿,业务代码零侵入。

Seata架构包含三个核心角色:TC(Transaction Coordinator)事务协调器,负责维护全局事务和分支事务的状态;TM(Transaction Manager)事务管理器,定义全局事务的开始、提交和回滚;RM(Resource Manager)资源管理器,管理分支事务上的本地资源。微服务架构中每个服务实例既是TM也是RM。

Seata Server部署与Nacos注册配置

Seata Server(TC)需要独立部署,生产环境建议使用Nacos作为注册中心和配置中心。以下是基于Docker的部署方案:

version: '3'
services:
  seata-server:
    image: seataio/seata-server:2.0.0
    container_name: seata-server
    ports:
      - "8091:8091"
      - "7091:7091"
    environment:
      - SEATA_IP=seata.example.com
      - SEATA_PORT=8091
      - STORE_MODE=db
      - SEATA_CONFIG_NAME=file:/root/seata-config/registry
    volumes:
      - ./seata-config:/root/seata-config
    depends_on:
      - mysql

registry.conf配置Nacos作为注册中心:

registry {
  type = "nacos"
  nacos {
    application = "seata-server"
    serverAddr = "nacos:8848"
    group = "SEATA_GROUP"
    namespace = ""
    cluster = "default"
    username = "nacos"
    password = "nacos"
  }
}

config {
  type = "nacos"
  nacos {
    serverAddr = "nacos:8848"
    group = "SEATA_GROUP"
    namespace = ""
    dataId = "seataServer.properties"
  }
}

STORE_MODE设置为db模式,事务日志持久化到数据库,相比file模式支持多TC节点高可用部署。Seata 2.0默认使用db存储模式,需要创建global_table、branch_table、lock_table三张表,建表SQL在Seata源码的script/server/db目录下。

Spring Boot集成Seata AT模式配置

微服务工程中集成Seata需要引入依赖并配置数据源代理。Maven依赖配置:

<dependency>
  <groupId>io.seata</groupId>
  <artifactId>seata-spring-boot-starter</artifactId>
  <version>2.0.0</version>
</dependency>
<dependency>
  <groupId>com.alibaba.nacos</groupId>
  <artifactId>nacos-client</artifactId>
  <version>2.3.0</version>
</dependency>

application.yml配置Seata客户端:

seata:
  enabled: true
  application-id: order-service
  tx-service-group: my_tx_group
  service:
    vgroup-mapping:
      my_tx_group: default
    grouplist:
      default: seata.example.com:8091
  registry:
    type: nacos
    nacos:
      server-addr: nacos:8848
      group: SEATA_GROUP
      application: seata-server
  config:
    type: nacos
    nacos:
      server-addr: nacos:8848
      group: SEATA_GROUP
  data-source-proxy-mode: AT

data-source-proxy-mode设置为AT后,Seata自动代理数据源,拦截SQL执行生成undo_log。业务代码无需任何改动,只需在事务入口添加@GlobalTransactional注解:

@Service
public class OrderService {

    @Autowired
    private OrderMapper orderMapper;
    @Autowired
    private InventoryFeignClient inventoryClient;
    @Autowired
    private AccountFeignClient accountClient;

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

        // 2. 扣减库存(远程调用,分支事务2)
        Result invResult = inventoryClient.deduct(dto.getProductId(), dto.getQuantity());
        if (!invResult.isSuccess()) {
            throw new RuntimeException("库存扣减失败: " + invResult.getMessage());
        }

        // 3. 扣减余额(远程调用,分支事务3)
        Result accResult = accountClient.debit(dto.getUserId(), dto.getAmount());
        if (!accResult.isSuccess()) {
            throw new RuntimeException("余额扣减失败: " + accResult.getMessage());
        }

        return order;
    }
}

当步骤3抛出异常时,TC会通知所有分支事务回滚。订单服务的undo_log记录了insert操作的反向SQL(DELETE),库存和账户服务各自执行补偿操作。整个回滚过程对业务代码透明。

undo_log表结构与回滚机制详解

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

CREATE TABLE `undo_log` (
  `branch_id` bigint NOT NULL COMMENT '分支事务ID',
  `xid` varchar(128) NOT NULL COMMENT '全局事务ID',
  `context` varchar(128) NOT NULL COMMENT '上下文',
  `rollback_info` longblob NOT NULL COMMENT '回滚信息',
  `log_status` int NOT NULL COMMENT '状态0正常1全局已完成',
  `log_created` datetime(6) NOT NULL COMMENT '创建时间',
  `log_modified` datetime(6) NOT NULL COMMENT '修改时间',
  `ext` varchar(100) DEFAULT NULL COMMENT '扩展字段',
  PRIMARY KEY (`branch_id`),
  KEY `idx_log_created` (`log_created`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

rollback_info字段存储JSON格式的回滚数据,包含执行前快照(beforeImage)和执行后快照(afterImage)。以UPDATE操作为例,beforeImage记录修改前的行数据,afterImage记录修改后的行数据。回滚时Seata根据beforeImage生成反向UPDATE SQL,将数据恢复到修改前状态。

对于INSERT操作,回滚SQL是DELETE;对于DELETE操作,回滚SQL是INSERT。Seata通过解析SQL语法树自动生成这些反向操作,开发人员不需要手动编写补偿逻辑。

高可用部署与常见问题诊断

Seata Server的高可用通过多实例部署实现。多个TC实例注册到同一个Nacos集群,客户端通过注册中心自动发现可用的TC节点。当某个TC实例宕机,客户端自动切换到其他实例。事务日志存储在共享的MySQL数据库中,保证状态一致性。

常见问题:全局事务超时

默认全局事务超时时间为60秒,复杂业务场景下可能不够。通过@GlobalTransactional注解的timeoutMills参数调整:

@GlobalTransactional(
    name = "create-order",
    timeoutMills = 120000,  // 120秒超时
    rollbackFor = Exception.class
)

超时后TC会主动触发全局回滚。如果业务方法执行时间超过超时时间,后续的分支事务注册会被拒绝。建议根据业务实际耗时设置合理的超时时间,预留30%的余量。

常见问题:undo_log清理

事务完成后undo_log记录会被标记为log_status=1,但不会立即删除。需要配置定时任务定期清理历史记录:

@Scheduled(cron = "0 0 2 * * ?")
public void cleanUndoLog() {
    // 删除7天前的已完成undo_log
    undoLogMapper.deleteExpired(LocalDateTime.now().minusDays(7));
}

也可以配置Seata的undo.log.save.days参数,由框架自动清理。默认保留7天,生产环境建议设置为3天以减少存储占用。

常见问题:数据源代理不生效

如果使用了Druid、HikariCP等连接池,需要确保Seata的数据源代理在连接池之上生效。检查启动日志中是否出现”Seata AT mode data source proxy”相关信息。如果使用了自定义DataSource Bean,需要手动包装为DataSourceProxy:

@Bean
public DataSource dataSource(DataSourceProperties properties) {
    HikariDataSource dataSource = properties
        .initializeDataSourceBuilder()
        .type(HikariDataSource.class)
        .build();
    return new DataSourceProxy(dataSource);
}

Seata AT模式通过自动化的SQL解析和undo_log机制实现了低侵入的分布式事务管理。配合Spring Boot的声明式事务注解,微服务架构下的跨库事务一致性可以像本地事务一样简单地处理。

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

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

相关推荐