news 2026/4/19 12:29:49

代购系统库存预占机制:防止超卖的分布式锁实现

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
代购系统库存预占机制:防止超卖的分布式锁实现

在代购、跨境电商等高并发下单场景中,库存超卖是最常见且代价极高的问题。多服务实例、多线程并发下单时,传统本地锁失效,极易导致库存校验与扣减出现竞态条件,最终出现 “无货可发、订单积压” 的故障。

本文围绕代购系统库存预占核心流程,讲解如何通过分布式锁实现安全库存预占,从原理、流程、代码实现到生产级优化,完整落地防超卖方案。


一、为什么代购系统必须做库存预占

代购业务有三大特性,决定库存必须 “先预占、后扣减”:

  1. 采购链路长:海外货源、清关、物流周期长,库存无法实时补货
  2. 并发集中:限时折扣、爆款补货瞬间流量高,并发冲突剧烈
  3. 支付异步:用户下单后需等待支付,未支付订单需释放库存

库存预占核心目标:下单时锁定库存,支付成功正式扣减,超时未支付自动释放,从根源杜绝超卖。


二、分布式锁解决超卖的核心原理

分布式锁的作用是跨服务、跨节点互斥,保证同一时间只有一个请求能操作同一商品库存。

核心流程:一锁二判三更新

  1. 加锁:对商品 ID 加分布式锁,阻塞并发请求
  2. 校验:查询真实可用库存,判断是否足够预占
  3. 预占:库存充足则写入预占记录,扣减可用库存
  4. 释放:业务完成释放锁,异常超时自动释放锁

满足三大特性:互斥性、防死锁、防误删,是防超卖的基础保障。


三、技术选型:Redis+Redisson 生产级方案

代购系统推荐Redis + Redisson实现分布式锁,理由:

  • 性能高,内存操作响应快
  • Redisson 封装完善,自带看门狗自动续期
  • 支持可重入、公平锁、联锁,适配复杂业务
  • 过期时间自动释放,避免服务宕机死锁

备选:ZooKeeper/etcd 一致性更强,但性能更低,适合强一致低并发场景。


四、库存预占完整实现流程

1. 数据结构设计

  • 库存总表:goods_id、total_stock、occupied_stock、available_stock
  • 预占记录表:preempt_id、goods_id、order_id、user_id、status、expire_time
  • 锁 Key:lock:goods:{goods_id}

2. 核心业务流程

  1. 用户提交下单请求
  2. 生成唯一请求 ID,尝试获取 Redisson 分布式锁
  3. 加锁成功:查询可用库存
  4. 库存不足:直接返回 “库存不足”,释放锁
  5. 库存充足:新增预占记录,更新可用库存与预占库存
  6. 开启支付超时任务(如 15 分钟)
  7. 释放分布式锁,返回下单成功
  8. 支付成功:正式扣减库存,删除预占记录
  9. 支付超时:定时任务回滚库存,释放预占

五、代码实现(Java + SpringBoot + Redisson)

1. 分布式锁工具类封装

java

运行

@Resource private RedissonClient redissonClient; /** * 获取分布式锁 * @param goodsId 商品ID * @param requestId 请求唯一ID * @return 锁对象 */ public RLock getGoodsLock(Long goodsId, String requestId) { String lockKey = "lock:goods:" + goodsId; RLock lock = redissonClient.getLock(lockKey); // 看门狗自动续期,默认30秒,每10秒续期 lock.lock(30, TimeUnit.SECONDS); return lock; } /** * 释放锁 */ public void unlock(RLock lock) { if (lock != null && lock.isHeldByCurrentThread()) { lock.unlock(); } }

2. 库存预占核心方法

java

运行

@Transactional(rollbackFor = Exception.class) public Result<?> preemptStock(Long goodsId, Integer num, String orderId, Long userId) { String requestId = UUID.randomUUID().toString(); RLock lock = null; try { // 1. 加分布式锁 lock = getGoodsLock(goodsId, requestId); // 2. 查询可用库存 GoodsStock stock = stockMapper.selectByGoodsId(goodsId); if (stock == null || stock.getAvailableStock() < num) { return Result.fail("库存不足"); } // 3. 写入预占记录 StockPreempt preempt = new StockPreempt(); preempt.setGoodsId(goodsId); preempt.setOrderId(orderId); preempt.setUserId(userId); preempt.setNum(num); preempt.setStatus(0); // 0-预占中 1-已扣减 2-已释放 preempt.setExpireTime(LocalDateTime.now().plusMinutes(15)); preemptMapper.insert(preempt); // 4. 更新库存:可用库存减少,预占库存增加 stockMapper.updateStock(goodsId, -num, num); return Result.success("库存预占成功"); } finally { // 5. 释放锁 unlock(lock); } }

3. 支付超时自动释放(定时任务)

java

运行

@Scheduled(cron = "0 */1 * * * ?") public void clearExpirePreempt() { // 查询超时预占记录 List<StockPreempt> list = preemptMapper.selectExpirePreempt(LocalDateTime.now()); for (StockPreempt preempt : list) { RLock lock = getGoodsLock(preempt.getGoodsId(), UUID.randomUUID().toString()); try { // 回滚库存:可用库存增加,预占库存减少 stockMapper.updateStock(preempt.getGoodsId(), preempt.getNum(), -preempt.getNum()); // 更新预占状态为已释放 preemptMapper.updateStatus(preempt.getId(), 2); } finally { unlock(lock); } } }

六、生产级防坑要点

  1. 锁粒度精细化按商品 ID 加锁,不锁全表,提升并发能力。

  2. 请求 ID 防误删释放锁时校验请求 ID,避免释放其他线程的锁。

  3. 看门狗必开Redisson 看门狗自动续期,防止业务未执行完锁过期。

  4. 数据库事务与锁顺序先加锁,后开启事务,避免长事务持有锁导致性能下降。

  5. 库存兜底校验更新库存时 SQL 增加条件:available_stock >= #{num},防止超卖。

    sql

    UPDATE goods_stock SET available_stock = available_stock - #{num}, occupied_stock = occupied_stock + #{num} WHERE goods_id = #{goodsId} AND available_stock >= #{num}
  6. 最终一致性保障定时任务 + 对账脚本,每日核对库存、预占、订单数据,修复异常。


七、方案对比与选型建议

表格

方案优点缺点适用场景
本地锁实现简单分布式失效单体应用
Redis 分布式锁高性能、易集成主从切换有极小锁失效风险代购 / 电商高并发下单
Redis+Lua 原子脚本性能极高业务逻辑复杂难维护秒杀、极致高并发
ZooKeeper 锁强一致性性能低金融、强一致场景

代购系统首选:Redis+Redisson 分布式锁,平衡性能、可靠性与开发成本。


八、总结

代购系统防超卖的核心是库存预占 + 分布式锁,通过 Redisson 实现跨节点互斥,配合预占超时释放机制,可 100% 避免超卖。

落地关键点:

  • 按商品 ID 细粒度加锁
  • 先锁后查,SQL 兜底校验
  • 支付超时自动回滚
  • 看门狗防止锁提前释放

这套方案可直接用于生产,支撑日常下单与爆款并发,稳定可靠。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/19 12:29:30

QMCDecode终极指南:3分钟解锁QQ音乐加密文件,实现音乐自由

QMCDecode终极指南&#xff1a;3分钟解锁QQ音乐加密文件&#xff0c;实现音乐自由 【免费下载链接】QMCDecode QQ音乐QMC格式转换为普通格式(qmcflac转flac&#xff0c;qmc0,qmc3转mp3, mflac,mflac0等转flac)&#xff0c;仅支持macOS&#xff0c;可自动识别到QQ音乐下载目录&a…

作者头像 李华
网站建设 2026/4/19 12:25:32

UndertaleModTool:开启GameMaker游戏深度修改的艺术之旅

UndertaleModTool&#xff1a;开启GameMaker游戏深度修改的艺术之旅 【免费下载链接】UndertaleModTool The most complete tool for modding, decompiling and unpacking Undertale (and other GameMaker games!) 项目地址: https://gitcode.com/gh_mirrors/un/UndertaleMod…

作者头像 李华
网站建设 2026/4/19 12:22:36

终极指南:3步让暗黑破坏神2在现代PC上焕发新生

终极指南&#xff1a;3步让暗黑破坏神2在现代PC上焕发新生 【免费下载链接】d2dx D2DX is a complete solution to make Diablo II run well on modern PCs, with high fps and better resolutions. 项目地址: https://gitcode.com/gh_mirrors/d2/d2dx D2DX是一个专为《…

作者头像 李华
网站建设 2026/4/19 12:19:58

OpenUserJS.org:如何构建你的第一个开源用户脚本平台

OpenUserJS.org&#xff1a;如何构建你的第一个开源用户脚本平台 【免费下载链接】OpenUserJS.org The home of FOSS user scripts. 项目地址: https://gitcode.com/gh_mirrors/op/OpenUserJS.org OpenUserJS.org 是一个基于 Node.js 构建的开源用户脚本托管平台&#x…

作者头像 李华
网站建设 2026/4/19 12:18:41

终极指南:用Python快速构建完整免费的金融数据自动化分析系统

终极指南&#xff1a;用Python快速构建完整免费的金融数据自动化分析系统 【免费下载链接】akshare AKShare is an elegant and simple financial data interface library for Python, built for human beings! 开源财经数据接口库 项目地址: https://gitcode.com/gh_mirrors…

作者头像 李华