跳转到主内容
极星编程网:以代码为星,赴技术山海!

SQL 分布式事务处理方法解析

MySQL XA在分库场景基本不可用,因协调者崩溃后无法全局判断分支状态,且各节点版本、binlog、时钟等不一致导致XA COMMIT失败;Seata AT需手动建全字段undo_log表;最终一致性方案更可控。 MySQL XA 事务为什么在分库场景下基本不可用 XA 协议理论上支持跨库两阶段提交,但实际在分库(比如 ShardingSphere 或自研分片)中几乎无法稳定落地。根本原因不是协议本身错,而是协调者(TM)和参与者(RM)的故障恢复能力严重不对等。 MySQL 的
XA RECOVER
只能查出本实例上未完成的 XA 分支,一旦 coordinator 崩溃,没有全局视图,无法判断哪些分支该 commit、哪些该 rollback 分库环境下,不同物理库的 MySQL 版本、binlog 格式、server_id 甚至时钟可能不一致,导致
XA PREPARE
成功后,某节点在崩溃恢复时拒绝
XA COMMIT
ShardingSphere 等中间件默认关闭 XA 支持,开启后需额外部署
Seata AT
或
Atomikos
,但它们对 MySQL 的 XA 日志解析有版本限制(例如不兼容 MySQL 8.0.33+ 的 redo log 优化) Seata AT 模式下 undo_log 表必须手动建且字段不能少 Seata 的 AT 模式靠本地
undo_log
表记录回滚日志,但它不会自动建表,也不校验表结构。很多团队上线后才发现事务卡住或回滚失败,根源是字段缺失或类型不匹配。 必须包含
branch_id
(BIGINT NOT NULL)、
xid
(VARCHAR(128) NOT NULL)、
context
(VARCHAR(128) NOT NULL)、
rollback_info
(LONGBLOB NOT NULL)、
log_status
(TINYINT NOT NULL)、
log_created
(DATETIME NOT NULL)、
log_modified
(DATETIME NOT NULL)
rollback_info
类型必须是
LONGBLOB
,用
TEXT
会导致大事务序列化失败,错误信息类似
java.io.EOFException: Unexpected end of ZLIB input stream
每个分库都要建同名同结构的
undo_log
表,Seata 不支持跨库路由该表 本地消息表 + 最终一致性比强一致更可控 真正线上扛量的分布式事务,90% 以上走的是“可靠消息 + 对账补偿”,而不是试图用框架模拟 ACID。它不依赖数据库层的复杂协调,出问题时可查、可重试、可人工介入。 消息表必须和业务表在同一库同一事务中写入,用
INSERT INTO msg_table (...) VALUES (...)
+
UPDATE biz_table SET status = 'sent' WHERE ...
包在同一个
BEGIN/COMMIT
里 投递服务轮询时要用
SELECT ... FOR UPDATE SKIP LOCKED
,避免多个 worker 重复取同一条消息;更新状态时要带条件,如
UPDATE msg_table SET status = 'sending' WHERE id = ? AND status = 'ready'
不要把重试逻辑全交给 MQ(比如 RabbitMQ 的死信队列),它的重试间隔不可控,且无法关联原始业务上下文;应由独立的调度服务管理重试次数、退避策略和告警阈值 TCC 接口的 Confirm/Cancel 必须幂等且不依赖 Try 阶段状态 TCC 是最灵活也最容易翻车的模式。很多人以为只要三个接口写出来就完事了,结果压测时大量
Confirm
失败,日志里反复出现
no try record found for xid
。
Confirm
和
Cancel
必须设计成纯幂等操作:比如扣库存用
UPDATE stock SET qty = qty - ? WHERE sku_id = ? AND qty >= ?
,而不是先
SELECT
再判断 不能假设
Try
一定成功或已落库——网络超时、应用重启都可能导致
Try
执行了但没返回响应,此时 Seata 会直接发
Confirm
,你的接口必须能凭
xid
和业务参数自行判断是否该执行
Cancel
不是
Try
的逆操作,而是“确保最终不发生”。例如
Try
预占额度,
Cancel
就是释放预占,哪怕预占记录已丢失,也要确保用户额度不被多扣 分布式事务真正的难点从来不在怎么写代码,而在于怎么定义“事务边界”——哪些操作必须原子,哪些可以妥协,以及当系统部分失联时,你愿意接受多久的数据不一致。这些决策没法靠框架自动做。

相关文章