谷粒商城实战笔记-281-商城业务-订单服务-锁定库存

创建订单时,有一个非常重要的步骤,就是锁定库存,或者称之为预占库存。

尽管还没有卖出去,但是因为订单已经创建,所以要确保这个订单对应商品是有库存的,就需要提前告知库存服务,需要准备多少库存,库存服务就会在当前库存基础上减去一部分库存,避免超卖。

一,锁定库存的基本逻辑

在这里插入图片描述

根据图片,锁定库存的逻辑可以概括为以下几个步骤:

  1. 商品尝试锁库存:这是库存锁定流程的开始,系统尝试对商品进行库存锁定。
  2. 增强版逻辑:增加了一些额外的判断或处理步骤。
  3. 撤销:在库存锁定过程中,如果遇到某些条件不满足,系统会执行撤销操作,释放已锁定的库存。
  4. 全部锁定:在某些情况下,系统可能会执行全部库存的锁定操作。
  5. 全部回滚:如果全部锁定操作失败或遇到问题,系统会执行全部回滚,即撤销所有已执行的锁定操作。
  6. 失败:在尝试锁定库存的过程中,如果遇到问题导致无法完成锁定,系统会标记为失败。
  7. 成功:如果库存锁定操作成功完成,系统会标记为成功。
  8. 修改锁定状态:在锁定过程中,系统可能需要根据实际情况修改库存的锁定状态。
  9. 返回:完成锁定或解锁操作后,系统会返回到上一步或初始状态。

这个过程看起来是一个自动化的库存管理流程,涉及到库存的锁定、解锁、状态修改等操作,并在操作过程中会有成功或失败的反馈。

二,具体实现

public boolean orderLockStock(WareSkuLockVo vo) {

        /**
         * 保存库存工作单详情信息
         * 追溯
         */
        WareOrderTaskEntity wareOrderTaskEntity = new WareOrderTaskEntity();
        wareOrderTaskEntity.setOrderSn(vo.getOrderSn());
        wareOrderTaskEntity.setCreateTime(new Date());
        wareOrderTaskService.save(wareOrderTaskEntity);


        //1、按照下单的收货地址,找到一个就近仓库,锁定库存
        //2、找到每个商品在哪个仓库都有库存
        List<OrderItemVo> locks = vo.getLocks();

        List<SkuWareHasStock> collect = locks.stream().map((item) -> {
            SkuWareHasStock stock = new SkuWareHasStock();
            Long skuId = item.getSkuId();
            stock.setSkuId(skuId);
            stock.setNum(item.getCount());
            //查询这个商品在哪个仓库有库存
            List<Long> wareIdList = wareSkuDao.listWareIdHasSkuStock(skuId);
            stock.setWareId(wareIdList);

            return stock;
        }).collect(Collectors.toList());

        //2、锁定库存
        for (SkuWareHasStock hasStock : collect) {
            boolean skuStocked = false;
            Long skuId = hasStock.getSkuId();
            List<Long> wareIds = hasStock.getWareId();

            if (org.springframework.util.StringUtils.isEmpty(wareIds)) {
                //没有任何仓库有这个商品的库存
                throw new NoStockException(skuId);
            }

            //1、如果每一个商品都锁定成功,将当前商品锁定了几件的工作单记录发给MQ
            //2、锁定失败。前面保存的工作单信息都回滚了。发送出去的消息,即使要解锁库存,由于在数据库查不到指定的id,所有就不用解锁
            for (Long wareId : wareIds) {
                //锁定成功就返回1,失败就返回0
                Long count = wareSkuDao.lockSkuStock(skuId,wareId,hasStock.getNum());
                if (count == 1) {
                    skuStocked = true;
                    WareOrderTaskDetailEntity taskDetailEntity = WareOrderTaskDetailEntity.builder()
                            .skuId(skuId)
                            .skuName("")
                            .skuNum(hasStock.getNum())
                            .taskId(wareOrderTaskEntity.getId())
                            .wareId(wareId)
                            .lockStatus(1)
                            .build();
                    wareOrderTaskDetailService.save(taskDetailEntity);

                    //TODO 告诉MQ库存锁定成功
                    StockLockedTo lockedTo = new StockLockedTo();
                    lockedTo.setId(wareOrderTaskEntity.getId());
                    StockDetailTo detailTo = new StockDetailTo();
                    BeanUtils.copyProperties(taskDetailEntity,detailTo);
                    lockedTo.setDetailTo(detailTo);
//                    rabbitTemplate.convertAndSend("stock-event-exchange","stock.locked",lockedTo);
                    break;
                } else {
                    //当前仓库锁失败,重试下一个仓库
                }
            }

            if (skuStocked == false) {
                //当前商品所有仓库都没有锁住
                throw new NoStockException(skuId);
            }
        }

        //3、肯定全部都是锁定成功的
        return true;
    }

orderLockStock 的方法为订单锁定库存。

  1. 保存库存工作单信息:

    • 创建一个新的 WareOrderTaskEntity 实体,并设置订单号 (orderSn) 和创建时间。
    • 保存这个实体到数据库。
  2. 查询并准备锁定库存的信息:

    • 获取传入的 WareSkuLockVo 对象中的 locks 列表,该列表包含需要锁定的商品信息。
    • 遍历 locks 列表,为每个商品创建一个 SkuWareHasStock 对象,其中包含商品 ID (skuId)、需要锁定的数量 (num) 以及拥有该商品库存的仓库列表 (wareIdList)。
  3. 锁定库存:

    • 遍历准备好的 SkuWareHasStock 对象列表。
    • 对于每个商品,检查是否有任何仓库有此商品的库存。如果没有,则抛出 NoStockException 异常。
    • 尝试在每个有库存的仓库中锁定商品:
      • 如果锁定成功(返回值为 1),则设置 skuStockedtrue,并保存一条库存锁定详情记录至数据库。
      • 创建一个消息对象 (StockLockedTo) 并填充相关信息,准备发送给消息队列以通知其他服务库存已锁定。
      • 如果所有尝试锁定的仓库都失败,则最终抛出 NoStockException 异常。
  4. 返回结果:

    • 如果所有商品的库存都成功锁定,则方法返回 true

这个方法实现了从接收库存锁定请求开始,经过库存锁定和状态记录,到最后通过消息队列通知其他服务库存锁定成功的一系列流程。

同时,它还处理了异常情况,如当商品没有库存时会抛出异常来确保系统的健壮性和一致性。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小手追梦

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值