https://www.nowcoder.com/feed/main/detail/5d0a7175e5a34ce987737faeb168b8cb
chatgpt
解决超卖问题是高并发场景下的一个关键挑战,特别是在商品秒杀或限时抢购的场景中。如果不进行恰当的设计,可能会导致超卖,即卖出的商品数量超过库存。以下是几种常见的解决超卖问题的方法:
Redis 提供的原子性命令(如 DECRBY
、INCRBY
)可以避免并发情况下的数据竞争。在高并发场景下,通过 Redis 的这些原子操作可以确保每次库存扣减是安全的。
库存判断和扣减结合
Redis 的 DECRBY
命令会在并发请求时保持操作的原子性,但不能单独依赖扣减后的结果,仍需要校验库存是否为负数。可以通过 Lua 脚本确保扣减库存和库存校验的原子性。例如:
local stock = redis.call('GET', KEYS[1])
if tonumber(stock) < tonumber(ARGV[1]) then
return -1 -- 返回库存不足
else
return redis.call('DECRBY', KEYS[1], ARGV[1])
end
通过这种方式,Redis 能够在高并发场景下通过原子操作保证每次库存扣减的正确性,避免超卖。
悲观锁:在数据库层面可以使用悲观锁,如 SELECT ... FOR UPDATE
,在查询库存的同时锁住相关记录,确保在这个事务内其他请求无法修改该库存,直到当前事务完成。例如:
START TRANSACTION;
SELECT stock FROM products WHERE product_id = 1001 FOR UPDATE;
-- 检查库存是否足够
UPDATE products SET stock = stock - 1 WHERE product_id = 1001;
COMMIT;
缺点是悲观锁在高并发场景下会严重影响性能,不适合高吞吐量的抢购场景。
乐观锁:另一种方式是使用乐观锁,通过版本号机制来避免并发修改库存导致超卖。每次更新库存时,检查该记录的版本号是否与之前一致,如果不一致则说明有其他请求已经更新了库存,操作失败。例子:
UPDATE products
SET stock = stock - 1, version = version + 1
WHERE product_id = 1001 AND version = 10;
如果返回的影响行数为 0,说明并发修改失败,需要重新尝试。
DECRBY
操作扣减库存;