---
title: TCC 与三大坑（空回滚/幂等/悬挂）
type: concept
domain: distributed-transaction
tags: [distributed-transaction, tcc, empty-rollback, idempotency, dangling, compensation, reconciliation]
status: learning
created: 2026-09-23
last_reviewed: 2026-09-23
method: feynman
related_questions:
  - "TCC 中，Confirm 或者 Cancel 失败了怎么办？"
related_knowledge:
  - ./distributed-tx-overview.md
  - ./seata-at.md
  - ./cross-border-payment-design.md
anki_cards: 8
interview_rounds:
  - "2026-09-23-round-2-Q6"
---

# TCC 与三大坑（空回滚/幂等/悬挂）

> TCC 是"准强一致"的分布式事务模式，业务实现 Try/Confirm/Cancel 三方法。三大坑（空回滚、幂等、悬挂）是评估团队 TCC 成熟度的试金石。重试的前提是幂等，幂等的前提是三大坑都处理好。

## TL;DR（30 秒扫完）

- **TCC 三方法**：Try 冻结资源 / Confirm 确认提交 / Cancel 取消补偿
- **三大坑**：空回滚（Try 未执行但 Cancel 到达）/ 幂等（Confirm/Cancel 重试）/ 悬挂（Confirm 先到被拒 Try 后到）
- **三大坑解决方案**：Try 标记表 / 业务单号唯一键 / 事务状态表
- **失败处理 6 步链路**：失败记录 → 幂等重试 → 超时兜底 → 告警 → 对账 → 人工
- **关键金句**：重试的前提是幂等，幂等的前提是三大坑都处理好
- **对账是终极兜底**：TCC 不是 100% 可靠，极端故障下靠对账发现不一致

## 关键结论

- **结论 A**：TCC 三大坑（空回滚/幂等/悬挂）必须同时处理，缺一不可
- **结论 B**：重试的前提是幂等，否则重试会重复扣款/重复发货
- **结论 C**：Seata TCC 框架已自动处理三大坑，自建 TCC 必须自己处理
- **结论 D**：对账系统是终极兜底，TCC + 对账 + 人工兜底是大厂金融标配

## 完整讲解（费曼四步）

### STEP 1 · 概念

**TCC（Try-Confirm-Cancel）**：业务显式实现三个方法的分布式事务模式，Try 冻结资源、Confirm 提交、Cancel 补偿。

### STEP 2 · 大白话

**TCC 类比**：你要买房，先交定金（Try），开发商确认合同（Confirm），最后过户（提交）。如果中间出问题，定金退还（Cancel）。
- **Try** = 交定金（冻结资源，不实际扣款）
- **Confirm** = 确认合同（真的扣款）
- **Cancel** = 定金退还（释放冻结）

**三大坑类比**：
- **空回滚** = 你还没交定金，但开发商说"退还定金"（Try 未执行但 Cancel 到达）
- **幂等** = 开发商重复让你签合同（Confirm 重试），重复扣款
- **悬挂** = 开发商先让你签合同但你还没交定金，然后你才交定金（Confirm 先到被拒，Try 后到）

### STEP 3 · 底层

#### TCC 三方法语义

| 方法 | 动作 | 示例（转账） |
|------|------|------------|
| **Try** | 冻结资源 | 冻结 A 账户 100 元（不实际扣款） |
| **Confirm** | 确认提交 | 真实扣款 A 账户 100 元 |
| **Cancel** | 取消补偿 | 释放 A 账户冻结的 100 元 |

#### 三大坑详解

| 坑 | 触发条件 | 表现 | 解决方案 |
|----|---------|------|---------|
| **空回滚** | Try 因网络问题从未执行，但 Cancel 因协调者崩溃恢复而到达 | Cancel 操作不存在的资源 | Try 标记表检查，未 Try 则 Cancel 直接返回成功 |
| **幂等** | Confirm/Cancel 因网络抖动被重试多次 | 重复扣款、重复发货 | 三个方法**全部**幂等（基于业务单号唯一键） |
| **悬挂** | Confirm 先到达被拒绝（无 Try 记录），随后 Try 才到，业务逻辑被 Try 执行了，但事务已判定失败 | 资源被占用但永远不释放 | 在 Try 前检查**事务状态表**，已确认/已取消则拒绝 Try |

#### 失败处理完整链路（6 步）

```
1. 失败记录：写失败日志 + 更新事务状态表（FAILED）
2. 幂等重试：定时任务扫 FAILED → 基于业务单号幂等执行
3. 超时兜底：重试 N 次仍失败 → 标记 NEED_MANUAL
4. 告警通知：短信/钉钉/飞书通知值班
5. 对账巡检：日终对账兜底，发现不一致生成差错账
6. 人工介入：工程师查失败现场，手工补偿
```

#### 超时回查机制

- Seata TCC 框架会**定期回查**分支事务状态
- 如果分支事务长时间未 Confirm，框架会主动询问："你成功了吗？"
- 业务方需要实现"状态查询接口"（如 `queryConfirmStatus(txn_id)`）

#### 对账系统的兜底作用

- TCC 不是 100% 可靠的，极端情况下（如 TC 故障 + 业务方宕机）仍可能不一致
- 对账系统是**最后一道防线**：日终/小时级扫描所有事务状态，发现不一致生成差错账
- 大厂金融系统标配：**TCC + 对账 + 人工兜底**

#### 工程最佳实践

- 使用 Seata TCC 框架（自动处理空回滚/幂等/悬挂）
- 自建 TCC 必须处理三大坑 + 超时回查 + 对账
- 失败重试次数建议 3-5 次，间隔指数退避（1s → 2s → 4s）
- 告警要分级：普通失败→钉钉，超时失败→电话/短信

### STEP 4 · 简化

> **一句话总结**：TCC 三大坑（空回滚/幂等/悬挂）必须同时处理；重试的前提是幂等，幂等的前提是三大坑都处理好；对账是终极兜底。

## 常见误区（从面试记录提炼）

- **误区 1**："TCC 的 Confirm/Cancel 失败了，只要重试就行" → 正确：重试的前提是**幂等**，否则重试会重复扣款/重复发货
- **误区 2**："TCC 只需要处理 Confirm/Cancel 失败" → 正确：TCC 有三大坑必须同时处理（空回滚/幂等/悬挂），不仅仅是失败重试
- **误区 3**："TCC 是 100% 可靠的" → 正确：TCC 不是 100% 可靠，极端故障下需要**对账系统**兜底
- **误区 4**："TCC 的三大坑是业务问题" → 正确：三大坑是**工程实践问题**，必须通过 Try 标记表/事务状态表/业务单号唯一键等技术手段解决
- **误区 5**："Seata TCC 不需要业务方做任何事" → 正确：Seata 已自动处理三大坑，但业务方仍需实现状态查询接口（超时回查）

## 延伸追问（面试追问预演）

1. **"TCC 的 Cancel 失败了，但是 Try 已经成功了，这时候业务数据处于什么状态？怎么恢复？"**
   - 要点：资源已被 Try 冻结但未 Cancel，状态悬挂。恢复：定时扫表查所有 Try 状态超过 T 的事务，强制 Cancel 并记录差错账

2. **"Seata TCC 框架的'超时回查'是怎么工作的？业务方需要做什么？"**
   - 要点：TC 定时扫描未完成的分支事务，调用业务方的 `queryConfirmStatus` 接口；业务方要实现状态查询接口

3. **"如果 TCC 框架都故障了，怎么兜底？"**
   - 要点：对账系统是终极兜底。日终对账对比所有事务的最终状态，发现不一致生成差错账，人工介入

4. **"TCC 和 Seata AT 都号称'强一致'，区别是什么？"**
   - 要点：AT 基于 undo log 自动回滚，对业务透明但需要全局锁；TCC 业务显式补偿，侵入高但锁粒度更细、可审计

5. **"TCC 的 Confirm 成功了但网络不通，协调者认为失败发了 Cancel，怎么办？"**
   - 要点：Cancel 必须幂等（已 Confirm 则直接返回成功）；靠事务状态表判断；对账系统兜底

## 速查表（一页扫完）

| 维度 | 内容 |
|------|------|
| **三方法** | Try 冻结 / Confirm 提交 / Cancel 补偿 |
| **三大坑** | 空回滚 / 幂等 / 悬挂 |
| **解决方案** | Try 标记表 / 业务单号唯一键 / 事务状态表 |
| **失败处理 6 步** | 记录→幂等重试→超时兜底→告警→对账→人工 |
| **超时回查** | TC 定期回查分支事务状态，业务方实现状态查询接口 |
| **对账兜底** | 日终/小时级对账，发现不一致生成差错账 |
| **关键金句** | "重试的前提是幂等，幂等的前提是三大坑都处理好" |

## 关联题目

- ⚠️ 《TCC 中，Confirm 或者 Cancel 失败了怎么办？》— 2026-09-23 Round 2 Q6, ⭐⭐⭐, 只答"记录+重试+人工"，漏三大坑和幂等

## 关联知识

- [分布式事务概览与模式分类](./distributed-tx-overview.md)
- [Seata AT 模式](./seata-at.md)
- [跨境支付方案设计](./cross-border-payment-design.md)

## Anki 候选卡片

**卡片 1**
- Q：TCC 的三个方法分别是什么？
- A：Try 冻结资源（不实际扣款）/ Confirm 确认提交（真的扣款）/ Cancel 取消补偿（释放冻结）

**卡片 2**
- Q：TCC 三大坑分别是什么？触发条件是什么？
- A：空回滚（Try 未执行但 Cancel 到达）/ 幂等（Confirm/Cancel 重试）/ 悬挂（Confirm 先到被拒 Try 后到）

**卡片 3**
- Q：TCC 三大坑的解决方案分别是什么？
- A：空回滚→Try 标记表检查，未 Try 则 Cancel 直接成功；幂等→三方法都基于业务单号做幂等；悬挂→Try 前检查事务状态表，已确认/已取消则拒 Try

**卡片 4**
- Q：TCC 失败处理的完整链路是什么？
- A：失败记录→幂等重试→超时兜底→告警通知→对账巡检→人工介入（6 步）

**卡片 5**
- Q：为什么重试的前提是幂等？
- A：Confirm/Cancel 重试时会多次执行，如果方法本身不幂等，就会重复扣款、重复发货

**卡片 6**
- Q：Seata TCC 框架的超时回查机制是怎么工作的？
- A：TC 定时扫描未完成的分支事务，调用业务方的 `queryConfirmStatus` 接口；业务方要实现状态查询接口

**卡片 7**
- Q：TCC 不是 100% 可靠的，怎么兜底？
- A：对账系统是终极兜底。日终对账对比所有事务的最终状态，发现不一致生成差错账，人工介入

**卡片 8**
- Q：TCC 和 Seata AT 都号称"强一致"，区别是什么？
- A：AT 基于 undo log 自动回滚，对业务透明但需要全局锁；TCC 业务显式补偿，侵入高但锁粒度更细、可审计
