Skip to content
困难

一句话答案

TCC 三阶段:Try(预留资源)→Confirm(确认提交)→Cancel(取消释放),灵活高性能但业务侵入大。

核心要点

TCC(Try-Confirm-Cancel): 一种业务层面的分布式事务解决方案,将每个操作分为三个步骤,由业务代码自己实现。

Try(尝试):预留/冻结资源,做业务检查
  → 不真正执行业务,只是资源预留

Confirm(确认):确认提交,执行真正的业务操作,使用 Try 阶段预留的资源
  → 不做任何业务检查,直接使用预留资源

Cancel(取消):释放 Try 阶段预留的资源
  → 回滚 Try 阶段的操作

转账案例(A 向 B 转 100 元):

Try 阶段:
  账户 A:检查余额 >= 100 → 冻结 100 元(frozen_amount += 100)
  账户 B:创建待入账记录(pending_amount += 100)

Confirm 阶段(所有 Try 成功后执行):
  账户 A:扣减冻结金额(balance -= 100, frozen_amount -= 100)
  账户 B:确认入账(balance += 100, pending_amount -= 100)

Cancel 阶段(任一 Try 失败后执行):
  账户 A:解冻金额(frozen_amount -= 100)
  账户 B:删除待入账记录(pending_amount -= 100)

TCC 实际使用的三大注意事项:

1. 幂等性(最关键): Confirm 和 Cancel 必须是幂等的。网络超时导致重试时,同一操作可能被执行多次。

java
// 幂等实现方案:用事务状态表记录执行状态
public void confirm(String txId) {
    // 先检查是否已经 Confirm 过
    TccRecord record = tccRecordMapper.selectByTxId(txId);
    if (record.getStatus() == CONFIRMED) {
        return; // 已确认过,直接返回(幂等)
    }
    // 执行 Confirm 逻辑...
    tccRecordMapper.updateStatus(txId, CONFIRMED);
}

2. 空回滚: Cancel 被调用时,Try 可能还没执行(网络延迟导致 Try 请求还没到)。Cancel 必须能处理这种情况——检测到 Try 未执行时,直接返回成功。

java
public void cancel(String txId) {
    TccRecord record = tccRecordMapper.selectByTxId(txId);
    if (record == null) {
        // Try 还没执行过 → 空回滚 → 插入一条记录标记已回滚
        tccRecordMapper.insert(txId, CANCELLED);
        return;
    }
    // 正常 Cancel 逻辑...
}

3. 悬挂(Suspension): 空回滚之后,迟到的 Try 请求才到达并执行——此时资源被预留但永远不会被 Confirm 或 Cancel(因为 Cancel 已经执行过了)。解决方案:Try 阶段先检查是否已经 Cancel 过,如果已 Cancel 则拒绝 Try。

java
public boolean tryAction(String txId) {
    TccRecord record = tccRecordMapper.selectByTxId(txId);
    if (record != null && record.getStatus() == CANCELLED) {
        return false; // 已经 Cancel 过了,拒绝 Try(防悬挂)
    }
    // 正常 Try 逻辑...
    tccRecordMapper.insert(txId, TRYING);
    return true;
}

TCC 优缺点:

优点缺点
无资源锁定,性能高业务侵入性大(每个操作都要写 Try/Confirm/Cancel)
最终一致性保证开发成本高(要处理幂等、空回滚、悬挂)
适合高并发金融场景维护成本高(业务变更需要同步修改三个方法)
追问与易错

追问方向:

  • 空回滚和悬挂问题?怎么解决?
  • Confirm/Cancel 失败怎么办?
  • TCC 比 2PC 好在哪?

易错点:

  • ❌ TCC 就是代码级的 2PC——TCC 一阶段就提交
  • ❌ 忘记处理空回滚

💡 记忆锚点

TCC 像饭店订座:Try=打电话预留座位(冻结资源),Confirm=到店入座(确认扣减),Cancel=取消预订(释放座位)。三大坑必须记:幂等(重复打电话别重复留座)、空回滚(没预留就取消要能处理)、悬挂(取消后迟到的预留要拒绝)。