redis 秒杀问题
模拟了一个秒杀的场景,发现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 加锁已经解决