redis 秒杀问题
发布于 3 年前 作者 DWNEWS-weiqingtao 2466 次浏览 来自 问答

模拟了一个秒杀的场景,发现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 回复

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

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

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

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

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

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

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

回到顶部