最近在实践中遇到一个分布式事务补偿机制的坑,分享一下踩坑经历。
我们团队在设计订单系统时,采用了基于消息队列的最终一致性方案。最初为了性能考虑,将事务隔离级别设置为READ_COMMITTED,结果导致了严重的数据不一致问题。
问题复现步骤:
- 用户下单,订单服务创建订单记录
- 库存服务扣减库存(未提交事务)
- 由于网络抖动,消息发送失败
- 补偿机制触发,但因为隔离级别低,读取到未提交的脏数据
- 最终出现超卖现象
代码示例:
@Transactional(isolation = Isolation.READ_COMMITTED)
public void processOrder(Order order) {
// 扣减库存
inventoryService.deductStock(order.getProductId(), order.getQuantity());
// 发送消息,但这里可能失败
messageSender.send("order_created", order);
}
后来我们改为使用REPEATABLE_READ隔离级别,并配合分布式锁机制。
@Transactional(isolation = Isolation.REPEATABLE_READ)
public void processOrder(Order order) {
// 加分布式锁
try (RedisLock lock = redisLockManager.acquire("order_lock_" + order.getId())) {
// 扣减库存
inventoryService.deductStock(order.getProductId(), order.getQuantity());
// 发送消息
messageSender.send("order_created", order);
}
}
经验教训:在补偿机制中,不能贪图性能而牺牲数据一致性。根据业务场景选择合适的隔离级别,必要时配合分布式锁来保证最终一致性。

讨论