美文网首页
关于库存

关于库存

作者: 小王ovo | 来源:发表于2023-06-14 11:29 被阅读0次

库存的核心(sql)

update product_skus set stock = stock - #{num} where id = id and stock >= num
或者
update product_skus set stock = stock - #{num} where (stock- #{num}) >= 0

缺点

虽然这句sql使用了乐观锁 stock >= num但是还是会有以下问题.(在mysql默认的rr隔离级别下,update语句会加锁,所以是串行执行的)。行级锁的原因存在性能瓶颈,高并发会出现请求堵塞超时问题。

其他方案(行锁 for update)

解决方案

将库存放入redis 使用INCR(原子自增+1)DECR(原子-1) INCRBY num(可以自定义加减数量) DECRBY
原子修改库存,伪代码如下.

秒杀场景

//判断用户是否已经购买
boolean exist = redisClient.query(productId,userId);
if(exist) {
  return -1;
}
//判断库存是否充足,如果扣减之后小于0则库存不足
if(redisClient.incrby(productId, -1)<0) {
  return 0;
}
//添加购买记录
redisClient.add(productId,userId);
return 1;

附带一个lua脚本

  StringBuilder lua = new StringBuilder();
  lua.append("if (redis.call('exists', KEYS[1]) == 1) then");
  lua.append("    local stock = tonumber(redis.call('get', KEYS[1]));");
  lua.append("    if (stock == -1) then");
  lua.append("        return 1;");
  lua.append("    end;");
  lua.append("    if (stock > 0) then");
  lua.append("        redis.call('incrby', KEYS[1], -1);");
  lua.append("        return stock;");
  lua.append("    end;");
  lua.append("    return 0;");
  lua.append("end;");
  lua.append("return -1;");

非秒杀场景

//判断库存是否充足,如果扣减之后小于0则库存不足
if(redisClient.decrby(productId, num)>=0) {
  //正常下单
}else{
  //库存不足,将扣减库存恢复至 redis
  redisClient.incrby(productId, num)
}

但是这样写两条命令就没有原子性了,在并发情况下一个请求库存不足,还没有恢复,另一个请求本来可以扣减成功,由于第一个请求还没有恢复导致扣减失败.可以使用redis锁或者lua脚本的方式保证两条命令的原子性.

订单取消、订单售后、取消支付等情况回滚库存

这种情况下并发并不高,直接使用数据库悲观锁恢复即可.记得同步redis.

管理后台调整库存,如何防止调整库存时,产生超卖

当作一种特殊的下单处理即可.

关于redis锁(保证加锁和设置失效时间的原子性)

为了防止redis中没有加载库存,大量请求打到数据库上的情况
这种方案下锁的粒度是sku(即单个商品).
1.使用set的方式加锁

String result = jedis.set(lockKey, requestId, "NX", "PX", expireTime);
if ("OK".equals(result)) {
    return true;
}
return false;
lockKey:锁的标识
requestId:请求id
NX:只在键不存在时,才对键进行设置操作。
PX:设置键的过期时间为 millisecond 毫秒。
expireTime:过期时间
  1. 使用自旋锁提高用户请求的成功率
try {
  Long start = System.currentTimeMillis();
  while(true) {
      String result = jedis.set(lockKey, requestId, "NX", "PX", expireTime);
     if ("OK".equals(result)) {
        return true;
     }
     
     long time = System.currentTimeMillis() - start;
      if (time>=timeout) {
          return false;
      }
      try {
          Thread.sleep(50);
      } catch (InterruptedException e) {
          e.printStackTrace();
      }
  }
 
} finally{
    unlock(lockKey,requestId);
}  
return false;

当然可以使用redission更好.

写在最后

1.扣减库存有下单减,支付减,建议下单减,支付减容易产生超卖;
2.在取消订单,支付回调,后台变更库存等边界点容易产生库存数据不准,要注意优化;
3.如果系统并发确实很高,可以考虑限流(令牌桶);

库存.png

相关文章

  • 商品为王的时代是用数据分析支撑商品管理

    一、关于商品分析 1、周转核算 周转天数=平均库存/月销售*月天数 平均库存=(月初库存+月底库存)/2 周转天数...

  • 关于仓库库存调拨的设置(竞品调研)

    一、关于期初库存的梳理: 胖猫云:定义为库存调整单,分为调整库存商品及新增商品,库存商品为已入库的商品,新增商品为...

  • iOS购物功能之Sku选择效果调研

    关于安卓Sku思路.——参考博客 相关概念: SKU=Stock Keeping Unit(库存量单位)。即库存进...

  • 关于电商中的库存分类

    可销售库存= 总库存 -订单占用库存-不可销售库存-锁定库存+虚库存+调拨占用库存 (一)可销售库存 指的...

  • 库存问题难解决?“牛鞭效应”是关键

    关于库存比例问题,曾有业界专家表示20%属于合理,但是各类别服装的生产企业在发展的各个阶段,合理库存的标准也有所不...

  • 电商产品库存扣减逻辑

    解读库存扣减逻辑: 1.库存主要分 总库存 冻结库存 可用库存 2.库存在提交订单的时候增加冻结库存并扣减可用库存...

  • 商品库存设计

    S=I-O-U-L-T+V 可销售库存=总库存-订单占用库存-不可销售库存-锁定库存-调拨占用库存+虚拟库存 可销...

  • 关于控制库存的思考

    背景:控制店铺库存,在合理的金额下对店铺的货品进行最大的合理利用。 方案一:TOP 产品的合理规划. 数据方面:T...

  • 快看!实力宠男粉!

    哈喽,各位!欢迎回到库存笔记的频道,为了平衡一下库存笔记男粉的内心,本期推出的内容是关于boy的穿搭指南,趁现在入...

  • 数据库精华备份

    http://www.itpub.net/thread-1393352-1-1.htmlhi,看到你关于数据库存储...

网友评论

      本文标题:关于库存

      本文链接:https://www.haomeiwen.com/subject/dmwhydtx.html