必须配置undo_log表,它是seata-golang at模式回滚的唯一数据依据,表名、字段类型(如rollback_info必须为longblob)、索引(idx_unionkey)均需严格匹配,且须与业务表同库同schema。

seata-golang 的 AT 模式必须配 undo_log 表
不建 undo_log 表,AT 模式根本跑不起来——它不是可选组件,而是 AT 回滚的唯一数据依据。Seata-golang 在执行 UPDATE、DELETE 等操作前会自动快照行数据,序列化后写入该表;回滚时就靠它还原状态。
建表语句必须严格匹配 Seata 版本要求(注意字段类型和索引):
CREATE TABLE `undo_log` ( `id` bigint NOT NULL 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, `ext` varchar(100) DEFAULT NULL, PRIMARY KEY (`id`), KEY `idx_unionkey` (`xid`,`branch_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
- 表名必须是
undo_log,不能加前缀或改名 -
rollback_info类型必须是longblob,用text或json会导致反序列化失败 -
idx_unionkey索引不可省略,否则高并发下查日志性能断崖下跌 - 该表需与业务表在同一个 MySQL 实例、同一 schema 下(Seata-golang 默认不跨库)
全局事务入口必须显式调用 Begin(),不能只靠注解
Go 没有运行时字节码增强能力,@GlobalTransactional 注解只是占位符,实际不生效。真正开启事务靠的是 globaltransaction.Begin() 手动调用,且必须在业务逻辑开始前、DB 操作之前完成。
常见错误是把 Begin() 放在 HTTP handler 最外层,但没传 context 或漏 defer Commit()/Rollback():
- 必须捕获 panic 并主动
Rollback(),否则异常退出时事务悬停 -
Begin()返回的*globaltransaction.GlobalTransaction要全程传递,不能丢弃 - 不要在 goroutine 里调用
Begin()—— XID 和分支上下文不跨协程传播 - 若用 ORM(如 GORM),需确保其底层
db.Begin()被 Seata 的代理tx替换,否则走原生事务,AT 失效
数据源必须走 Seata 代理,raw sql.Open 不行
直接 sql.Open("mysql", dsn) 创建的 *sql.DB 完全绕过 Seata,所有 SQL 都变成本地事务。必须用 Seata 提供的代理初始化方式:
import "github.com/seata/seata-go/pkg/datasource/sql"
db, err := sql.Open("mysql", dsn) // 注意:这里用的是 seata-go 的 sql 包
if err != nil {
panic(err)
}
// 启用 AT 代理
proxyDB := sql.NewDB(db, sql.WithATMode())
-
sql.Open必须导入github.com/seata/seata-go/pkg/datasource/sql,不是标准库 -
NewDB()返回的*sql.DB才具备解析 SQL、生成 undo 日志、注册分支事务的能力 - 如果业务已用 GORM,需替换其
gorm.Open()的dialector,用seata-gorm适配器(社区有非官方封装),否则 AT 拦截失效 - 连接池参数(如
SetMaxOpenConns)要设在代理后的proxyDB上,而非原始db
TC 地址和事务分组配置稍有偏差就会静默失败
Seata-golang 启动时不报错,但后续所有分支注册都超时或 404,大概率是 seatago.yml 里 vgroup-mapping 或 service.grouplist 写错了。
典型配置片段(注意层级和缩进):
seata:
application-id: "order-svc"
tx-service-group: "default_tx_group"
service:
vgroup-mapping:
default_tx_group: "default"
grouplist:
default: "127.0.0.1:8091"
-
tx-service-group值(如default_tx_group)必须和代码中globaltransaction.Begin()的group参数一致 -
vgroup-mapping的 key 是事务分组名,value 是集群名(如default);grouplist的 key 是集群名,value 是 TC 地址 - 地址格式必须是
host:port,不能带http://或路径 - TC 服务必须已启动且健康(访问
http://localhost:7091应返回 dashboard 页面)
最易被忽略的是:Seata-golang 默认使用 TCP 协议连 TC,而某些网络环境(如 Kubernetes Pod 间通信)可能默认阻断非 HTTP 端口,需确认 8091 端口可达。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











