账户服务日志里 Cancel 先于 Try 到达,冻结金额被减了两次,可用余额比流水合计多出 300。Try 随后才进来,又冻了一次。第一次遇到会往复杂处想,其实漏掉的多是个小前提。
SELECT xid, branch_id, status FROM tcc_branch
WHERE xid = 'TX20260301001';
INSERT INTO tcc_branch(xid, branch_id, status)
VALUES ('TX20260301001', 'acct-freeze', 'CANCELLED');
全局事务超时后在协调器侧被判失败,直接下发 Cancel,而 Try 还堵在网关重试队列里。Cancel 没有先查 Try 是否执行过,空回滚改动了本来就不存在的冻结记录。这一点先确认清楚,后面就不用反复试。
碰到「TCC 空回滚」这类问题,我习惯先把当前配置原样备份一份,改坏了立刻换回来,不用现场推。新版本先放一台机器上跑一天再全量,问题一般在这段时间暴露。
备份不是备了就行,恢复一次才算数,很多备份文件打开才发现是空的。
具体做法是,Cancel 先按事务号查分支记录 没有 Try 就写一条空回滚标记直接返回;分支记录加事务号加分支号的唯一约束;Try 进来先看空回滚标记 有就拒绝执行;Cancel 的金额更新带上原冻结金额作为条件。
改完照着核一遍,先发 Cancel 再发 Try 时 Cancel 成功且不动余额 Try 被标记拒绝 冻结金额只减一次。
