1、问题

img

2、目标

  • 不超卖、不少卖
  • 防止恶意刷单

3、系统大图

img

4、行动

img

5、重要流程

5.1、库存操作流程

5.1.1、下单时占用库存

  • 校验订单是否存在“占用”库存操作流水

    • 如果存在,则处理过,无需再次处理
  • 对订单id加“占用”Redis锁

    • 解决同一个订单并发请求占用库存问题
  • 再次校验订单是否存在“占用”库存操作流水

    • 避免在加锁的时,另外的线程产生数据
  • 获取商品的剩余库存GoodsStockResidueCacheBizReadService.queryGoodsStockResidueFromCache

  • 扣减redis商品剩余库存

  • 开启事务,批量更新商品库存表、批量插入库存操作流水表,提交事务

    • 如果出现异常,回滚事务,并恢复redis商品剩余库存

5.1.2、订单取消释放库存

  • 根据订单id查询是否存在“确认”库存操作流水

    • 如果存在,则表明次订单已经付款结束
  • 根据订单id查询是否存在“释放”库存操作流水

    • 如果存在,则处理过释放库存操作,无需再次处理
  • 对订单id加上“释放-确认”Redis锁,解决同一个订单,并发释放、确认库存问题

    • key goodsStockReleaseConfirmLockPrefix:${orderId}
  • 再次根据订单id查询是否存在“确认”库存操作流水

  • 再次根据订单id查询是否存在“释放”库存操作流水

  • 根据订单id查询“占用”库存操作流水

  • 循环所有商品,查询redis中的剩余库存数量(防止数据未初始化)

  • 开启事务

  • 批量更新数据库中的商品库存、批量插入释放库存操作流水

  • 增加Redis中商品库存剩余数量

  • 提交事务

  • 如果出现异常,事务会滚,并恢复redis库存剩余数量

5.1.3、订单支付成功确认库存

  • 根据订单id查询是否存在“释放”库存操作流水

    • 如果存在,则表明次订单已经取消订单
  • 根据订单id查询是否存在“确认”库存操作流水

    • 如果存在,则处理过确认过库存操作,无需再次处理
  • 对订单id加上“释放-确认”Redis锁,解决同一个订单,并发释放、确认库存问题

  • 根据订单id查询是否存在“释放”库存操作流水

  • 根据订单id查询是否存在“确认”库存操作流水

  • 根据订单id查询“占用”库存操作流水

  • 开启事务,批量插入确认库存操作流水,提交事务

5.2、限购校验流程

  • 查询数据库中商品限购数量

    • 因为商品下架后,才能修改商品限购数量,所以下单时,限购数量不会发生改变
  • 判断商品是否限购,如果不限购,直接跳过校验

  • 如果商品限购,查询查询goods_sell_log表(库存流水表)

    • 锁定库存总数=释放库存总数+确认库存总数+当前锁定库存数
  • 当前用户已下单(包括已支付和未支付)商品数量 = 确认库存总数+当前锁定库存数 =锁定库存总数-释放库存总数

  • 判断当前用户已下单商品数是否达到商品限购数

6、结果

  • 成功保障活动
  • 两千万营业额