CNode

redis 秒杀问题

问答
DDWNEWS-weiqingtao发布于5 年前最后回复5 年前4 回复3097 浏览0 收藏

模拟了一个秒杀的场景,发现count为0,但是有多个用户买了,麻烦大佬看看,谢谢! 代码如下:

  async buy(ctx) {
    try {
      await redis.watch("goods_count");
      const count = await redis.get("goods_count");
      if (parseInt(count) > 0) {
        console.log(count);
        const time = new Date();
        const at = Math.round(time / 1000);
        const data = await redis.multi().zadd("user_goods_list", at, uuid.v4()).set("goods_count", count - 1).exec();
        console.log(data);
        ctx.body = {
          message: "抢到了"
        }
      } else {
        ctx.body = {
          message: "goods is empty"
        }
      }
    } catch (error) {
      console.log(error)
      ctx.body = {
        message: "fail"
      }
    }
  }
查看回复

回复 (4)

F
fengwenxiu#1·5 年前

const count = await redis.get("goods_count"); 这一句并发的时候,大家都是 0 ,所以你这个判断失效了。可以先加后取。用 INCR。

H
hyj1991#2·5 年前

秒杀要把 查询库存 -> 下单 -> 更新库存 这三步当成一个事务来处理,开始前就用 setnx 加锁

要不然假如实际库存是1,这是后来个三个并发的用户请求 redis 查询到库存都是 1,那这三个人都可以下单导致超卖了

N
netwjx#3·5 年前

await redis.get("goods_count"); await redis.multi().zadd("user_goods_list", at, uuid.v4()).set("goods_count", count - 1).exec();

全都不是原子操作 你需要由一个原子操作的结果, 来确定后续的业务操作

比如 incr -> 有效 用返回值继续后续的zadd操作 无效 直接结束 不需要get

D
DWNEWS-weiqingtao#4·5 年前

谢谢大家的回答 用了setnx 加锁已经解决

参与回复
登录后即可参与回复。登录