本文目录导读:

- 案例背景:电商下单
- TCC 核心概念映射
- 完整业务时序图(正常流程)
- 核心代码逻辑(Java 伪代码)
- 异常情况与幂等性处理(重点)
- TCC 的优缺点总结(案例复盘)
- 实际应用框架
- 案例分析总结:关键点
这是一个关于TCC(Try-Confirm-Cancel) 分布式事务模式的详细案例解析,TCC 是解决微服务架构下数据一致性问题的常用方案,尤其适用于强一致性要求较高的业务场景。
为了让你能直观理解,我将通过一个电商下单扣库存的经典案例,从业务背景到代码逻辑再到异常处理进行全流程拆解。
案例背景:电商下单
假设我们有三个微服务:
- 订单服务:创建订单。
- 库存服务:扣减商品库存。
- 账户服务:扣减用户余额。
业务需求:用户下单时,需要同时创建订单、扣减库存、扣减余额,这三个操作必须要么全部成功,要么全部失败(不能出现订单创建了但库存没扣,或者钱扣了但订单没创建的情况)。
TCC 核心概念映射
TCC 将每个业务操作拆分为两个阶段(Try 阶段 + Confirm/Cancel 阶段),针对上述业务,我们定义如下:
| 服务 | Try(预留资源) | Confirm(确认执行业务) | Cancel(取消/回滚预留资源) |
|---|---|---|---|
| 库存服务 | 冻结库存(将商品库存从“可用”转为“冻结”) | 扣减库存(将“冻结”的库存删除) | 解冻库存(将“冻结”的库存回退为“可用”) |
| 账户服务 | 冻结金额(将用户余额从“可用”转为“冻结”) | 扣减金额(将“冻结”的金额扣除) | 解冻金额(将“冻结”的金额回退为“可用”) |
| 订单服务 | 创建订单(状态:待确认) | 更新订单(状态:已确认/成功) | 更新订单(状态:已取消/关闭) |
完整业务时序图(正常流程)
用户请求下单
|
| (1) 全局事务管理器(TM)发起事务
v
+-------------------+
| Try 阶段 | <-- 尝试预留资源(此时并未真正扣减,只是“占坑”)
+-------------------+
| (2) 调用库存服务 -> 冻结库存 100 件(成功)
| (3) 调用账户服务 -> 冻结余额 1000 元(成功)
| (4) 调用订单服务 -> 创建订单(状态:待确认,成功)
v
(若全部 Try 成功)
|
| (5) TM 发起 Confirm 提交
v
+-------------------+
| Confirm 阶段 | <-- 真正执行业务变更
+-------------------+
| (6) 库存服务 -> 扣减冻结库存(成功)
| (7) 账户服务 -> 扣减冻结余额(成功)
| (8) 订单服务 -> 更新订单状态为“支付成功”(成功)
v
全局事务完成,所有数据最终一致。
核心代码逻辑(Java 伪代码)
这是最关键的部分,也就是如何保证数据一致性。
库存服务
// 库存表
// 字段:total_stock(总库存), frozen_stock(冻结库存)
/** Try 阶段:锁定库存 */
@Transactional // 本地事务,保证该步骤内的操作原子性
public boolean tryDeductStock(Long productId, int quantity) {
// 1. 检查可用库存是否足够:total_stock - frozen_stock >= quantity
// 2. SQL: UPDATE stock SET frozen_stock = frozen_stock + ?
// WHERE product_id = ? AND (total_stock - frozen_stock) >= ?
// 3. 如果影响行数为 0,返回 false(表示库存不足,触发 Cancel)
return true; // 或者抛出异常
}
/** Confirm 阶段:真正扣减 */
@Transactional
public boolean confirmDeductStock(Long productId, int quantity) {
// 1. 将“冻结库存”转为“扣减”
// SQL: UPDATE stock SET total_stock = total_stock - ?,
// frozen_stock = frozen_stock - ? WHERE product_id = ?
return true;
}
/** Cancel 阶段:解冻库存 */
@Transactional
public boolean cancelDeductStock(Long productId, int quantity) {
// 1. 释放“冻结库存”
// SQL: UPDATE stock SET frozen_stock = frozen_stock - ?
// WHERE product_id = ?
return true;
}
账户服务(逻辑类似,略)
异常情况与幂等性处理(重点)
分布式事务最大的挑战在于网络超时和机器宕机。
场景 1:Try 阶段部分失败(例如库存不足)
库存服务 Try 成功(冻结库存)。
2. 账户服务 Try 失败(余额不足,抛出异常)。
3. 全局事务管理器(TM)收到失败信号。
-> TM 调用 **Cancel** 接口,回滚之前成功的 Try 操作。
即调用库存服务的 Cancel——将冻结的库存解冻。
**结果**:虽然库存 Try 成功,但最终被 Cancel,数据库没有留下脏数据。
场景 2:Confirm 阶段超时(网络抖动)
所有 Try 成功。 2. TM 调用库存服务 Confirm(成功),但网络超时,TM 未收到响应。 3. TM 调用库存服务 Confirm(重试)。 **核心问题**:如果第一次 Confirm 成功了,第二次重复调用 Confirm 会导致库存被重复扣减! **解决方案(幂等性)**: 必须确保 Confirm 和 Cancel 接口是**幂等**的。 - 在数据库表中添加 **事务日志表** 或 **状态字段**(如 `tx_id`)。 - 执行 Confirm 前,先查询该 `tx_id` 是否已处理过。 - 如果已处理,直接返回成功,不再执行扣减逻辑。
场景 3:Cancel 阶段失败(极端情况)
Cancel 也失败了(例如数据库宕机),TM 会不断重试,直到成功。 如果一直失败,则需要进入“人工介入”或“定时对账”流程。
TCC 的优缺点总结(案例复盘)
优点
- 强一致性:相比 MQ 的最终一致性,TCC 在 Confirm 阶段完成后数据是强一致的。
- 业务隔离:Try 阶段通过“冻结”资源,不会占用其他正常用户的可用资源,并发效率高(例如库存不足时,其他人依然可以购买其他商品)。
- 灵活性高:可以根据业务逻辑定制 Confirm 和 Cancel,不局限于数据库操作。
缺点
- 开发成本高:每个业务都需要实现
Try、Confirm、Cancel三个方法,代码量翻倍。 - 侵入性强:业务逻辑需要改造,将原本的单库事务拆分为两阶段。
- 对“空回滚”和“悬挂”要求高:需要处理中间状态(Try 还没执行完,Cancel 就来了)。
- 不适合简单的读多写少场景:太重了。
实际应用框架
在实际开发中,你不会手写这些逻辑,通常会使用成熟的分布式事务框架:
- Seata(阿里开源,推荐):
@GlobalTransactional注解 + 自动生成TCC模式。 - Hmily:网易开源的 TCC 框架。
- ByteTCC。
案例分析总结:关键点
这个案例的核心思想是:“先占坑,后填坑”。
- Try:不真正扣钱/扣货,而是把你的账号余额“冻结”起来,把仓库的商品“锁住”。
- Confirm:既然大家都有货也有钱,那就正式“扣款扣货”。
- Cancel:只要有一方不行(没钱或没货),立刻把之前“冻结”的全部释放。
注意:TCC 并不能解决所有问题,它在设计时牺牲了一定的吞吐量和极高的实现复杂度,用于换取数据的强一致性,在业务中对资金、库存敏感度极高的场景(如电商支付、秒杀)中应用广泛。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播