找回密码
 立即注册
首页 业界区 业界 高并发下如何防止商品超卖?

高并发下如何防止商品超卖?

钱闲华 2025-6-3 12:55:04
前言

"快看我们的秒杀系统!库存显示-500了!"
3年前的这个电话让我记忆犹新。
当时某电商大促,我们自认为完美的分布式架构,在0点整瞬间被击穿。
数据库连接池耗尽,库存表出现负数,客服电话被打爆...
今天这篇文章跟大家一起聊聊商品超卖的问题,希望对你会有所帮助。
1 为什么会发生超卖?

首先我们一起看看为什么会发送超卖?
1.1 数据库的"最后防线"漏洞

我们用下面的列子,给大家介绍一下商品超卖是如何发生的。
  1. public boolean buy(int goodsId) {
  2.     // 1. 查询库存
  3.     int stock = getStockFromDatabase(goodsId);
  4.     if (stock > 0) {
  5.         // 2. 扣减库存
  6.         updateStock(goodsId, stock - 1);
  7.         return true;
  8.     }
  9.     return false;
  10. }
复制代码
在并发场景下可能变成下图这样的:
1.webp

请求1和请求2都将库存更新成9。
根本原因:数据库的查询和更新操作,不是原子性校验,多个事务可能同时通过stock>0的条件检查。
1.2 超卖的本质

商品超卖的本质是:多个请求同时穿透缓存,同一时刻读取到相同库存值,最终在数据库层发生覆盖。
就像100个人同时看上一件衣服,都去试衣间前看了眼牌子,出来时都觉得自己应该拿到那件衣服。
2 防止超卖的方案

2.1 数据库乐观锁

数据库乐观锁的核心原理是通过版本号控制并发。
例如下面这样的:
  1. UPDATE product
  2. SET stock = stock -1, version=version+1
  3. WHERE id=123 AND version=#{currentVersion};
复制代码
Java的实现代码如下:
  1. @Transactional
  2. public boolean deductStock(Long productId) {
  3.     Product product = productDao.selectForUpdate(productId);
  4.     if (product.getStock() <= 0) return false;
  5.    
  6.     int affected = productDao.updateWithVersion(
  7.         productId,
  8.         product.getVersion(),
  9.         product.getStock()-1
  10.     );
  11.     return affected > 0;
  12. }
复制代码
基于数据库乐观锁方案的架构图如下:
2.webp

优缺点分析
优点缺点无需额外中间件高并发时DB压力大实现简单可能出现大量更新失败适用场景:日订单量1万以下的中小系统。
2.2 Redis原子操作

Redis原子操作的核心原理是使用:Redis + Lua脚本。
核心代码如下:
  1. // Lua脚本保证原子性
  2. String lua = "if redis.call('get', KEYS >= ARGV[1] then " +
  3.              "return redis.call('decrby', KEYS[1], ARGV " +
  4.              "else return -1 end";
  5. public boolean preDeduct(String itemId, int count) {
  6.     RedisScript<Long> script = new DefaultRedisScript<>(lua, Long.class);
  7.     Long result = redisTemplate.execute(script,
  8.         Collections.singletonList(itemId), count);
  9.     return result != null && result >= 0;
  10. }
复制代码
该方案的架构图如下:
3.webp

性能对比
<ul>单节点QPS:数据库方案500 vs Redis方案8万
响应时间:
您需要登录后才可以回帖 登录 | 立即注册