SELECT transfer_no, from_shard, to_shard, from_status, to_status
FROM transfer_global
WHERE from_status <> to_status
  AND create_time > '2026-03-01';

账户表按 user_id 分了 8 个库,转账双方落在不同片,扣款那片提交成功,入账那片抛连接超时,重试脚本跑完两边金额还是对不上。先别急着动参数,把报错原文和时间点记下来,顺序反了容易白折腾。

原因不复杂,同一个逻辑事务被拆到两个物理库,@Transactional 只覆盖当前数据源。第二个库失败时第一个库已经提交,本地事务没有跨库回滚能力。

这次卡住的地方就在「分库分表跨片事务」这一环,单独把它拎出来验证,别和其他改动混在同一次发布里。改动写完就同步给同事,下一个人踩同一个坑,成本还是你的。

处理上按这个顺序:跨片转账改用 TCC 或本地消息表加补偿 不要指望单库事务;按转账单号落一条全局流水 记录两个分片状态;每个分片操作都带转账单号做幂等;对账按全局流水核对两边 差额自动进补偿。

改完只确认一件事:跨片转账失败时两个分片状态都能在全局流水里看到 差额单会被补偿任务处理掉。

作者 9823189