场景如下:
订单系统收到第三方支付平台支付成功的通知后,需要进行1:更新订单的状态为已支付 2:扣减商品库存
订单库:
订单表order:orderID、userID、status
商品库:
商品库存表productStock:productStockID、productID、stock
出库单outStockBill:outStockBillID、orderID、stock
正常流程为:支付成功后根据orderID更新对应订单的状态status为已支付,并且扣减商品库存ProductStock(将stock减少),插入出库单outStockBill(其中的orderID为支付的订单ID)
更新订单状态和扣减商品库存是2个相互独立的服务,这就产生了分布式事务的问题,如订单状态更新了,但是扣减库存失败;当然解决方案有多种,这里考虑的做法是通过消息表的形式来实现。
在订单库里新增一个更新库存消息表,整个系统现有的数据库和表如下
订单库:
订单表order:orderID、userID、status
库存扣减消息表stockMsg:stockMsgID、orderID、status(1:待确认 2:已确认)
商品库:
商品库存表productStock:productStockID、productID、stock
出库单outStockBill:outStockBillID、orderID、stock
处理流程如下:
1:更新订单状态为已支付,并插入一条待确认的记录到库存扣减信息表,该记录的orderID为支付成功的订单ID,这一步在同一个事务中进行
2:更新商品库存,并插入出库单,出库单中的orderID为支付成功的订单ID,这一步也在同一个事务中进行
3:更新库存扣减消息表的状态为已确认
系统后台开启一个定时任务,定时轮训消息表中待确认的消息,
1:首先调用接口判断该消息中的订单是否存在于出库单中(消息中有订单ID,出库单中也有订单ID)
2:如果不存在则并调用接口更新商品库存、插入出库单,更新消息状态为已确认;如果更新消息失败,继续上一步操作
3:如果存在,则将消息状态更新为已确认,如果这一步中更新消息失败,回到第一步
那么会存在下列几种情况
编号 | 更新订单、插入消息 | 更新库存、插入出库单 | 更新消息表 |
1 | 成功 | 成功 | 成功 |
2 | 成功 | 成功 | 失败 |
3 | 成功 | 失败 | 不操作 |
4 | 失败 | 不操作 | 不操作 |
情况1:数据一致性没有问题
情况2:这个时候消息是待确认状态,定时轮训的时候会查询到对应订单的出库单,所以不再进行库存更新操作,而是直接更新消息状态为已确认,数据最终一致
情况3:这个时候消息是待确认状态,定时轮训的时候会查询不到对应订单的出库单,所以会进行库存更新操作,库存更新后将消息状态为已确认,数据最终一致
4:整个流程失败,数据一致性没有破坏