使用Lua脚本来确保商品扣减的原子操作

  StringBuilder sb = new StringBuilder();
        sb.append(" local table = {}  "); // 你要扣减的key :product.1
        sb.append(" local values =  redis.call('mget',  unpack(KEYS) )"); // [product.1,product.2]   =>  product.1 product.2
        sb.append(" for i = 1, #KEYS   do  ");
        sb.append("   if  tonumber(ARGV[i]) > tonumber(values[i])   then ");
        sb.append("     table[#table + 1] =  KEYS[i] .. '=' .. values[i] "); // product.1=23
        sb.append("   end ");
        sb.append(" end ");
        sb.append(" if #table > 0 then ");
        sb.append("   return table  ");
        sb.append(" end ");
        sb.append(" for i = 1 , #KEYS do ");
        sb.append("   redis.call('decrby',KEYS[i],ARGV[i])  ");
        sb.append(" end ");
        sb.append(" return {} ");
        RedisScript<List> luaScript = RedisScript.of(sb.toString(), List.class);

          List<StockProduct> stockProducts =  new ArrayList<>();
          stockProducts.add(new StockProduct(5,1));
          stockProducts.add(new StockProduct(4,2));

        List<String> keys = stockProducts.stream().map(it -> "product." + it.getId()).collect(Collectors.toList());
        Object[] qtys = stockProducts.stream().map(it -> it.getQty() + "").toArray();
        List<String> list = stringRedisTemplate.execute(luaScript,
                keys,
                qtys);
        if(list.isEmpty()){
            System.out.println("库存冻结成功");
        } else {

            for (String key_qty : list) {
                String[] split = key_qty.split("=");
                System.out.println(split[0] + "库存不足,剩余库存量:" + split[1]);
            }

        }


        ThreadUtil.safeSleep(3000);

 sb2.append("for i = 1, #KEYS do ")
                .append(" redis.call('incrby', KEYS[i], ARGV[i]) ")
                .append("end ")
                .append("return 'ok' ");

 /**
     * 取消订单并回补库存
     *
     * @param decreaseRequests 订单中的商品信息及每件商品需要回补的数量。每个订单项包含商品 ID 和回补数量。
     *                         这个列表中的每个元素表示一个需要回补库存的商品。
     */
    public String increase(List<DecreaseRequest> decreaseRequests) {

        // 将构建的 Lua 脚本字符串封装为 RedisScript 对象,指定脚本返回值的类型为 String。
        RedisScript<String> luaScript = RedisScript.of(sb2.toString(), String.class);

        // 根据订单中的商品信息构建回补库存操作所需的 Redis 键(商品 ID)和值(回补数量)。
        List<String> keys = decreaseRequests.stream()
                .map(it -> redisInventory + it.getProductId())
                .collect(Collectors.toList());
        List<String> quantities = decreaseRequests.stream()
                .map(DecreaseRequest::getCount)
                .map(Object::toString)
                .collect(Collectors.toList());


        String[] values = ArrayUtil.toArray(quantities, String.class);
        // 执行 Lua 脚本,回补库存。keys 是库存键列表,quantities 是对应每个键(商品)的回补数量。
        String result = stringRedisTemplate.execute(luaScript, keys, values);

        // 根据执行结果,记录日志。如果执行成功,则为每个回补的商品记录成功信息;如果执行失败,则记录失败原因。
        if ("ok".equals(result)) {
            decreaseRequests.forEach(it -> {
                log.debug("订单 {} 回补库存成功,商品 ID:{},商品名称:{},回补数量为:{}", it.getOrderId(), it.getProductId(), it.getProductName(), it.getCount());
            });
            return result;
        } else {
            log.error("库存回补失败");
        }

        return "error";
    }


  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值