Seata TCC模式详解(底层原理与实现 + Java代码示例)
一、TCC模式底层原理详解
1. 三阶段流程详解
-
Try阶段:
- 核心任务:预留业务资源,检查业务规则
- 关键操作:
- 执行业务检查(如库存是否充足)
- 执行不改变业务状态的预留操作(如减库存但不改变订单状态)
- 记录业务状态为"预留中"
- 特点:必须保证幂等性,防止重复执行导致资源重复预留
-
Confirm阶段:
- 核心任务:确认执行业务操作
- 关键操作:
- 检查业务状态是否为"预留中"
- 执行真正的业务操作(如将订单状态更新为"已支付")
- 更新业务状态为"已完成"
- 特点:必须保证幂等性,防止重复确认导致业务状态异常
-
Cancel阶段:
- 核心任务:取消预留的资源
- 关键操作:
- 检查业务状态是否为"预留中"
- 执行补偿操作,释放预留的资源(如恢复库存)
- 更新业务状态为"已取消"
- 特点:必须保证幂等性,防止重复取消导致资源异常
2. 底层实现机制
-
业务状态管理:
- 使用状态机管理业务状态流转
- 将业务状态持久化到数据库
- 通过状态控制流程走向
-
幂等性设计:
- Try阶段:检查当前状态是否允许预留
- Confirm阶段:检查当前状态是否为"预留中"
- Cancel阶段:检查当前状态是否为"预留中"
-
异常处理:
- Try阶段失败:直接回滚,无需进入后续阶段
- Confirm/Cancel阶段失败:记录日志,可能需要人工干预或重试
-
事务传播:
- XID通过ThreadLocal传递
- 在远程调用时通过RPC框架传递XID
- 确保同一全局事务的所有分支使用相同的XID
3.TCC流程图
文章中的mermaid 经常报错 直接生成图片 贴出来
二、Java代码示例
1. 业务服务接口
public interface OrderService {
// Try阶段:预留订单资源
boolean tryCreateOrder(Order order);
// Confirm阶段:确认创建订单
void confirmCreateOrder(Order order);
// Cancel阶段:取消订单预留
void cancelCreateOrder(Order order);
}
2. 业务实现类
@Service
public class OrderServiceImpl implements OrderService {
@Autowired
private OrderMapper orderMapper;
@Autowired
private InventoryService inventoryService;
@Override
public boolean tryCreateOrder(Order order) {
// 1. 检查订单是否已存在(幂等性检查)
Order existOrder = orderMapper.findByOrderId(order.getOrderId());
if (existOrder != null) {
return false; // 订单已存在,幂等性保证
}
// 2. 检查库存(幂等性检查)
if (!inventoryService.checkStock(order.getProductId(), order.getNum())) {
return false;
}
// 3. 预留库存(幂等性操作)
inventoryService.reduceStock(order.getProductId(), order.getNum());
// 4. 创建订单(幂等性操作)
order.setStatus("待支付");
orderMapper.insert(order);
return true;
}
@Override
public void confirmCreateOrder(Order order) {
// 1. 检查订单状态(幂等性检查)
Order dbOrder = orderMapper.findByOrderId(order.getOrderId());
if (dbOrder == null || !"待支付".equals(dbOrder.getStatus())) {
throw new RuntimeException("订单状态不正确,无法确认");
}
// 2. 确认订单状态(幂等性操作)
order.setStatus("已支付");
orderMapper.updateStatus(order);
}
@Override
public void cancelCreateOrder(Order order) {
// 1. 检查订单状态(幂等性检查)
Order dbOrder = orderMapper.findByOrderId(order.getOrderId());
if (dbOrder == null || !"待支付".equals(dbOrder.getStatus())) {
throw new RuntimeException("订单状态不正确,无法取消");
}
// 2. 取消订单(幂等性操作)
order.setStatus("已取消");
orderMapper.updateStatus(order);
// 3. 恢复库存(幂等性操作)
inventoryService.restoreStock(order.getProductId(), order.getNum());
}
}
3. 业务调用示例
@Service
public class BusinessService {
@Autowired
private OrderService orderService;
@GlobalTransactional // 开启全局事务
public void placeOrder(Order order) {
// Try阶段
boolean tryResult = orderService.tryCreateOrder(order);
if (!tryResult) {
throw new RuntimeException("订单预留失败");
}
// 其他业务操作...
// 如果所有操作成功,Seata会自动调用Confirm
// 如果任何操作失败,Seata会自动调用Cancel
}
}
三、TCC模式关键点
-
幂等性设计:
- 每个阶段的方法必须保证幂等性
- 防止重复执行导致数据不一致
-
业务状态管理:
- 使用状态机管理业务状态
- 通过状态控制流程走向
-
异常处理:
- Try阶段失败直接回滚
- Confirm/Cancel阶段需要处理异常
-
性能考虑:
- Try阶段尽量轻量
- Confirm/Cancel阶段可以异步执行
四、TCC模式适用场景
-
适合场景:
- 业务逻辑复杂,需要精细控制事务
- 需要预留资源的场景(如库存、优惠券)
- 跨多个服务的业务流程
-
不适合场景:
- 简单的数据库事务
- 对性能要求极高的场景
- 不需要预留资源的简单操作
五、TCC模式最佳实践
-
设计原则:
- Try阶段只做检查和不改变业务状态的预留操作
- Confirm阶段执行真正的业务操作
- Cancel阶段执行补偿操作
-
状态管理:
- 使用状态机管理业务状态
- 通过状态控制流程走向
-
异常处理:
- 对每个阶段的方法进行异常捕获
- 记录详细的日志便于排查问题
-
性能优化:
- 减少远程调用次数
- 合理设计事务边界
TCC模式虽然实现复杂度较高,但在需要精细控制事务的场景下提供了最大的灵活性,是Seata分布式事务方案中处理复杂业务逻辑的重要模式。