跨服务场景下的分布式事务一致性保障

CalmSilver +0/-0 0 0 正常 2025-12-24T07:01:19 分布式事务 · 消息队列 · 最终一致性

在跨服务场景下,分布式事务一致性保障是架构设计的核心挑战。本文分享一个实用的最终一致性解决方案。

问题场景:用户下单后需要同时调用库存服务扣减库存和订单服务创建订单,两个操作必须保证原子性。

解决方案:基于消息队列的最终一致性方案

  1. 核心思路:使用本地消息表 + 消息队列实现事务解耦

  2. 具体实现步骤

    • 订单服务创建订单记录,状态为"待处理"
    • 调用库存服务扣减库存(异步)
    • 库存服务扣减成功后,发送消息到MQ
    • 消息消费者监听MQ,收到消息后更新订单状态为"已完成"
  3. 代码示例

// 订单服务
@Transactional
public void createOrder(Order order) {
    orderRepository.save(order);
    // 调用库存服务
    inventoryService.reduceStock(order.getProductId(), order.getQuantity());
    
    // 本地消息表记录
    MessageRecord record = new MessageRecord();
    record.setOrderId(order.getId());
    messageRepository.save(record);
}

// 消息消费者
@RabbitListener(queues = "order.queue")
public void handleOrderMessage(OrderMessage message) {
    orderRepository.updateStatus(message.getOrderId(), "completed");
}
  1. 关键保障机制
    • 本地消息表确保消息发送的可靠性
    • 消息重试机制避免网络异常
    • 定时任务检查未完成的消息

该方案在保证数据一致性的同时,有效解耦了服务间的依赖关系。

推广
广告位招租

讨论

0/2000
冬日暖阳
冬日暖阳 · 2026-01-08T10:24:58
这方案把分布式事务拆成两个阶段,看似解耦了,但其实还是在用消息队列做补偿,本质上是牺牲了强一致性换来了可用性。建议加上幂等性校验和状态机设计,避免重复处理导致的数据不一致。
幻想的画家
幻想的画家 · 2026-01-08T10:24:58
本地消息表+MQ的套路很常见,但容易忽略的是库存扣减失败后的回滚逻辑。如果库存服务挂了或者超时,订单状态就永远卡在‘待处理’,建议加个定时任务兜底,主动检查并触发补偿机制。
ShallowSong
ShallowSong · 2026-01-08T10:24:58
代码示例里事务只包了订单保存,没包含消息记录,这其实是个隐患。正确的做法应该是把消息发送和订单更新放在同一个本地事务里,否则一旦消息发出去但订单回滚了,就会出现数据不一致