Seata 分布式事务协调与模式配置
seata 是开源的分布式事务解决方案,包含 TC(事务协调者,seata-server)、TM(事务管理器,发起全局事务)和 RM(资源管理器,管理分支事务)。一次全局事务有唯一 XID,分支注册到 TC,由 TC 决定提交或回滚。
它解决跨服务、跨数据库的业务一致性,提供 AT、TCC、SAGA、XA 四种模式。AT 模式对业务侵入最小:RM 拦截 SQL、记录 undo_log,一阶段本地提交并持有全局锁,二阶段删除日志或反向补偿;TCC 由业务实现 Try/Confirm/Cancel;SAGA 用状态机和补偿;XA 依赖数据库 XA 协议,强一致但锁持有时间长。
与“本地消息表 + 最终一致”相比,Seata 提供统一的回滚协调,但引入 TC 和全局锁,吞吐与运维成本更高。短事务、强一致选 AT/XA;长流程、外部系统选 SAGA;资金类、需要资源预留选 TCC。生产至少部署 3 个 TC,并使用 db/redis/raft 存储,避免 file 模式单点。
sh bin/seata-server.sh -p 8091 -h 0.0.0.0 -m file
ss -lntp | grep -E '7091|8091'
8091 是 TC 服务端口,7091 是 1.5+ 的控制台端口;-m 指定 store 模式。业务库必须先建 undo_log:
CREATE TABLE IF NOT EXISTS `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(6) NOT NULL,
`log_modified` DATETIME(6) NOT NULL,
UNIQUE KEY `ux_undo_log` (`xid`, `branch_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
发起全局事务与 TCC 接口:
@GlobalTransactional(timeoutMills = 30000, name = "create-order")
public void createOrder(Long userId, Long skuId) {
orderService.create(userId, skuId);
stockService.deduct(userId, skuId);
}
@TwoPhaseBusinessAction(name = "deduct", commitMethod = "commit", rollbackMethod = "rollback")
public boolean prepare(BusinessActionContext ctx, Long userId, Long skuId) { return true; }
public boolean commit(BusinessActionContext ctx) { return true; }
public boolean rollback(BusinessActionContext ctx) { return true; }
常用排查 SQL:
SELECT xid, status, application_id, transaction_service_group FROM global_table WHERE xid = 'x';
SELECT xid, branch_id, resource_id, status FROM branch_table WHERE xid = 'x';
SELECT xid, table_name, pk, status FROM lock_table WHERE xid = 'x';
seata.enabled=true
seata.application-id=order-service
seata.tx-service-group=my_tx_group
seata.service.vgroup-mapping.my_tx_group=default
seata.service.grouplist.default=127.0.0.1:8091
seata.registry.type=nacos
seata.registry.nacos.server-addr=127.0.0.1:8848
seata.config.type=nacos
seata.config.nacos.server-addr=127.0.0.1:8848
seata.data-source-proxy-mode=AT
客户端默认 client.tm.defaultGlobalTransactionTimeout=60000、client.rm.lock.retryInterval=10、retryTimes=30,提交/回滚重试次数默认 5。服务端 store.mode 默认 file,集群要用 db/redis/raft;DB 存储需要 global_table、branch_table、lock_table、distributed_lock 等表。
@GlobalTransactional 不生效:同类自调用、private/final 方法、对象不是 Spring Bean,都会绕过代理;检查日志里是否生成 XID。seata.enable-auto-data-source-proxy=true,Bean 是 DataSourceProxy,XA 模式还要设置 data-source-proxy-mode=XA。Table 'undo_log' doesn't exist 或列缺失:每个业务库都要执行与版本匹配的 undo_log 脚本,旧脚本可能没有 context 列。LockConflictException 或 get global lock fail;默认每 10ms 重试、共 30 次,检查 lock_table 并缩短事务或做业务重试。no available service 'default' found:vgroup 映射、注册中心 namespace/group、8091 连通性不一致;查 TC 日志和注册中心实例。timeoutMills 并处理回滚竞态。@TwoPhaseBusinessAction 的 name 要唯一。