库存扣减方案

3,009 阅读2分钟
折戟沉沙铁未销,自将摩洗认前朝。
东风不与周郎便,铜雀春深锁二乔。
《赤壁》—— 杜牧

方案描述

创建订单时预占库存,预占成功,则进行订单创建。 用户支付成功后,发送扣减库存消息到MQ,库存服务进行库存真正扣减; 订单取消,发送释放库存消息到MQ,库存服务释放库存。

序列图

流程说明:

1~3. 将库存同步到redis中

4~5. 下单,订单服务发起预占库存请求(根据订单号)

  1. 库存服务进行库存判断和预占

    /**
     * 预占库存 伪代码
     * @param orderNo 订单号
     * @param skuId sku标识
     * @param quantity 预占数量
     */
    boolean preOccupy(String orderNo, String skuId, int quantity) {
    
    	boolean isPreOccupySuccess = false;
        
        int value = redis.decrby(skuId, quantity);
        if (value >= 0) {
        	// 库存充足
            // 生成库存预占流水记录(关键字段:orderNo,skuId,quantity,state(0-预占;1-已扣减;2-已释放)
            
            isPreOccupySuccess = true;
        
        } else {
        	// 库存不足,返还刚才预占的库存
            redis.incrby(skuId, qunatity);
        }
        	
        
    }
    
  2. 返回库存预占结果

    1)预占成功,继续下单流程

    2)预占失败,库存不足,无法创建订单

  3. 支付成功,订单服务发送扣减库存消息到MQ

  4. 订单取消,订单服务发送释放库存消息到MQ

  5. 库存服务接收到消息:

    1)扣减库存消息,库存预占流水对应记录状态更新为已扣减

    2)释放库存消息,库存预占流水对应记录状态更新为已释放,库存表和redis中返还相应的库存

备注

可以增加库存调度服务,对超过一定时间的预占库存进行释放: 假如订单超时是30分钟,则调度服务可以查询出处于预占状态的超时的流水(大于30分钟),向订单服务确认是否下单成功,如果成功,则修改状态为已扣减,如果失败,则返还库存