高并发秒杀系统如何锁住库存

 

博主介绍:✌全网粉丝5W+,全栈开发工程师,从事多年软件开发,在大厂呆过。持有软件中级、六级等证书。可提供微服务项目搭建与毕业项目实战,博主也曾写过优秀论文,查重率极低,在这方面有丰富的经验✌

博主作品:《Java项目案例》主要基于SpringBoot+MyBatis/MyBatis-plus+MySQL+Vue等前后端分离项目,可以在左边的分类专栏找到更多项目。《Uniapp项目案例》有几个有uniapp教程,企业实战开发。《微服务实战》专栏是本人的实战经验总结,《Spring家族及微服务系列》专注Spring、SpringMVC、SpringBoot、SpringCloud系列、Nacos等源码解读、热门面试题、架构设计等。除此之外还有不少文章等你来细细品味,更多惊喜等着你哦

🍅uniapp微信小程序🍅面试题软考题免费使用,还可以使用微信支付,扫码加群。由于维护成本问题得不到解决,可能将停止线上维护。

🍅文末获取联系🍅精彩专栏推荐订阅👇🏻👇🏻 不然下次找不到哟

Java项目案例《100套》
https://blog.csdn.net/qq_57756904/category_12173599.html
uniapp小程序《100套》

https://blog.csdn.net/qq_57756904/category_12173599.html

有需求代码永远写不完,而方法才是破解之道,抖音有实战视频课程,某马某千等培训都是2万左右,甚至广东有本科院校单单一年就得3万4年就12万学费,而且还没有包括吃饭的钱。所以很划算了。另外博客左侧有源码阅读专栏,对于求职有很大帮助,当然对于工作也是有指导意义等。在大城市求职,你面试来回一趟多多少少都在12块左右,而且一般不会一次性就通过,还得面试几家。而如果你对源码以及微服务等有深度认识,这无疑给你的面试添砖加瓦更上一层楼。

最后再送一句:最好是学会了,而不是学废了!!

2

在秒杀系统中,库存锁定是防止超卖的关键环节。以下是几种高效可靠的库存锁定方案:

一、Redis原子操作方案(推荐)

1. 基于DECR的原子扣减

public boolean lockStockWithRedis(Long itemId, int quantity) {String key = "seckill:stock:" + itemId;// Lua脚本保证原子性String script ="local stock = tonumber(redis.call('get', KEYS[1])) " +"if stock >= tonumber(ARGV[1]) then " +"   return redis.call('decrby', KEYS[1], ARGV[1]) " +"else " +"   return -1 " +"end";Long result = redisTemplate.execute(new DefaultRedisScript<>(script, Long.class),Collections.singletonList(key),String.valueOf(quantity));return result != null && result >= 0;
}

2. 分布式锁+库存扣减

public boolean lockStockWithDistributedLock(Long itemId, int quantity) {String lockKey = "seckill:lock:" + itemId;RLock lock = redissonClient.getLock(lockKey);try {// 尝试加锁,等待时间100ms,锁持有时间30sif (lock.tryLock(100, 30000, TimeUnit.MILLISECONDS)) {try {String stockKey = "seckill:stock:" + itemId;Long stock = redisTemplate.opsForValue().get(stockKey);if (stock != null && stock >= quantity) {redisTemplate.opsForValue().decrement(stockKey, quantity);return true;}} finally {lock.unlock();}}} catch (InterruptedException e) {Thread.currentThread().interrupt();}return false;
}

二、数据库方案

1. 乐观锁实现

@Update("UPDATE item_stock SET stock = stock - #{quantity}, version = version + 1 " +"WHERE item_id = #{itemId} AND stock >= #{quantity} AND version = #{version}")
int deductStockWithOptimisticLock(@Param("itemId") Long itemId, @Param("quantity") int quantity,@Param("version") int version);

2. 悲观锁实现

@Select("SELECT * FROM item_stock WHERE item_id = #{itemId} FOR UPDATE")
ItemStock selectForUpdate(Long itemId);public boolean lockStockWithPessimisticLock(Long itemId, int quantity) {// 在事务中执行ItemStock stock = stockMapper.selectForUpdate(itemId);if (stock.getStock() >= quantity) {stock.setStock(stock.getStock() - quantity);stockMapper.update(stock);return true;}return false;
}

三、预扣库存方案

1. 两阶段库存锁定

public boolean twoPhaseLockStock(Long itemId, int quantity, String orderNo) {// 第一阶段:预扣Redis库存if (!lockStockWithRedis(itemId, quantity)) {return false;}// 第二阶段:异步持久化mqTemplate.send("stock_prelock_topic", new StockLockEvent(itemId, quantity, orderNo));return true;
}// 消费者处理
public void handleStockLock(StockLockEvent event) {try {// 数据库最终扣减int updated = stockMapper.realDeduct(event.getItemId(), event.getQuantity());if (updated <= 0) {// 回滚RedisredisTemplate.opsForValue().increment("seckill:stock:" + event.getItemId(), event.getQuantity());// 标记订单失败orderService.markAsFailed(event.getOrderNo());}} catch (Exception e) {// 异常处理}
}

四、库存分段方案(应对热点商品)

public boolean segmentLockStock(Long itemId, int quantity) {// 将库存分成16个段final int SEGMENTS = 16;int segment = (int) (itemId % SEGMENTS);String segmentKey = "seckill:stock:seg:" + itemId + ":" + segment;// 每个段维护部分库存Long remain = redisTemplate.opsForValue().decrement(segmentKey, quantity);if (remain != null && remain >= 0) {return true;} else {// 回滚redisTemplate.opsForValue().increment(segmentKey, quantity);return false;}
}

五、库存回滚机制

public boolean rollbackStock(Long itemId, int quantity) {String key = "seckill:stock:" + itemId;Long result = redisTemplate.opsForValue().increment(key, quantity);// 同时记录回滚流水stockFlowMapper.insert(new StockFlow(itemId, "ROLLBACK", quantity));return result != null;
}

六、库存状态检查

public StockLockResult checkStockLock(String orderNo) {// 检查订单状态Order order = orderMapper.selectByNo(orderNo);if (order == null) {return StockLockResult.notFound();}// 检查库存锁定状态String lockKey = "seckill:lock:" + order.getItemId() + ":" + orderNo;boolean locked = redisTemplate.hasKey(lockKey);if (order.getStatus() == OrderStatus.PAID) {return StockLockResult.success();} else if (locked) {return StockLockResult.locking();} else {return StockLockResult.failed();}
}

七、方案对比

方案优点缺点适用场景
Redis原子操作性能高,实现简单需要保证Redis高可用绝大多数秒杀场景
乐观锁无额外依赖高并发下重试率高并发量适中的场景
悲观锁强一致性性能差,可能死锁对一致性要求极高的场景
预扣库存用户体验好实现复杂需要快速响应的场景
库存分段减少竞争库存分配需合理超级热点商品

最佳实践建议

  1. 组合使用:Redis原子操作 + 异步数据库更新 + 定时核对

  2. 监控报警

    • 库存锁定成功率

    • Redis库存与数据库库存差异

    • 锁定/释放比例异常

  3. 压测验证:模拟峰值流量验证锁库存逻辑

  4. 兜底方案

    // 库存锁定兜底检查
    @Scheduled(fixedRate = 60000)
    public void checkStockConsistency() {List<Item> items = itemMapper.selectAll();items.forEach(item -> {Long redisStock = redisTemplate.opsForValue().get("seckill:stock:" + item.getId());if (redisStock != null && !redisStock.equals(item.getStock())) {alarmService.notify("库存不一致:" + item.getId());}});
    }

通过以上方案,可以有效解决秒杀系统中的库存锁定问题,在保证系统高并发的条件下防止超卖现象。

3

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/901226.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【Docker】Dockerfile 编写实践

&#x1f47b;创作者&#xff1a;丶重明 &#x1f47b;创作时间&#xff1a;2025年4月8日 &#x1f47b;擅长领域&#xff1a;运维 目录 1. Dockerfile编写原则1.1.选择合适的基础镜像1.2.镜像层优化1.3.多阶段构建1.4.安全增强 2. 关键指令与技巧2.1.COPY vs ADD2.2.ENTRYPOIN…

【数学建模】(智能优化算法)萤火虫算法(Firefly Algorithm)详解与实现

萤火虫算法(Firefly Algorithm)详解与实现 文章目录 萤火虫算法(Firefly Algorithm)详解与实现前言1. 算法原理2. 算法流程3. Python实现4. 算法特点4.1 优点4.2 缺点 5. 应用领域6. 算法变种7. 总结与展望参考文献 前言 大家好&#xff0c;今天给大家介绍一种有趣且高效的群体…

VSCode会击败Cursor和Windsurf吗?

VSCode 会击败 Cursor 和 Windsurf 吗&#xff1f;微软能不能靠自己的地盘优势和规则限制打压对手&#xff1f;答案是"能"&#xff0c;但他们真的会这么干吗&#xff1f; Cursor & Windsurf vs VSCode Copilot 大PKAI编程工具大战越来越激烈现在最火最赚钱的AI…

2025-4-11 情绪周期视角复盘(mini)

简单说两句好了&#xff0c;做一个阶段记录&#xff0c;目前阶段就是上一轮 中毅达 第二轮补涨的退潮结束&#xff0c;回盛生物 金河生物 它们的题材导致 农业和医药这2个题材退潮&#xff0c;注意的是不靠谱导致的反制题材是在这个二轮补涨周期里一起走的&#xff0c;所以 海…

【SLAM】将realsense-viewer录制的rosbag视频导出成图片序列(RealSense D435)

本文介绍了如何将realsense-viewer录制的rosbag格式的视频导出成图片序列&#xff0c;方便合并成mp4视频或插入到论文中。 本文首发于❄慕雪的寒舍 说明 Intel提供的realsense-viewer软件录制的视频都是rosbag格式的&#xff0c;为了编写论文&#xff0c;需要从录制的视频中截…

Ubuntu ROS 对应版本

Ubuntu 18.04 (Bionic Beaver) - 2018年4月发布 对应的ROS版本&#xff1a;ROS Melodic (2018年5月发布) Ubuntu 20.04 (Focal Fossa) - 2020年4月发布 对应的ROS版本&#xff1a;ROS Noetic (2020年5月发布) Ubuntu 22.04 (Jammy Jellyfish) - 预计2022年4月发布 对应的ROS版…

Ubuntu 软件卸载与清理终极指南

Ubuntu 软件卸载与清理指南 适用范围&#xff1a;Ubuntu 及其衍生发行版&#xff08;如 Linux Mint、Pop!_OS 等&#xff09;&#xff0c;Debian 系统大部分方法也适用。 目标&#xff1a;帮助你快速、彻底卸载软件并清理残余文件&#xff0c;保持系统整洁。 前提&#xff1a;建…

基于javaweb的SpringBoot新闻视频发布推荐评论系统(源码+部署文档)

技术范围&#xff1a;SpringBoot、Vue、SSM、HLMT、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、小程序、安卓app、大数据、物联网、机器学习等设计与开发。 主要内容&#xff1a;免费功能设计、开题报告、任务书、中期检查PPT、系统功能实现、代码编写、论文编写和辅导、论文…

Linux-内核驱动

open uboot.bin target-connect U-Boot&#xff08;Universal Boot Loader&#xff09;是一种广泛使用的开源引导加载程序&#xff0c;它允许用户从各种设备&#xff08;如硬盘、USB设备、网络等&#xff09;加载操作系统。U-Boot提供了丰富的命令行接口&#xff08;CLI&#…

DAPP实战篇:使用ethers.js连接以太坊智能合约

专栏:区块链入门到放弃查看目录-CSDN博客文章浏览阅读344次。为了方便查看将本专栏的所有内容列出目录,按照顺序查看即可。后续也会在此规划一下后续内容,因此如果遇到不能点击的,代表还没有更新。声明:文中所出观点大多数源于笔者多年开发经验所总结,如果你想要知道区块…

[原创](现代Delphi 12指南): 设置、运行和调试你的第一个macOS应用程序.

[作者] 常用网名: 猪头三 出生日期: 1981.XX.XX 企鹅交流: 643439947 个人网站: 80x86汇编小站 编程生涯: 2001年~至今[共24年] 职业生涯: 22年 开发语言: C/C、80x86ASM、Object Pascal、Objective-C、C#、R、Python、PHP、Perl、 开发工具: Visual Studio、Delphi、XCode、C …

Adobe Photoshop 2025 Mac中文 Ps图像编辑

Adobe Photoshop 2025 Mac中文 Ps图像编辑 一、介绍 Adobe Photoshop 2025 Mac版集成了多种强大的图像编辑、处理和创作功能。①强化了Adobe Sensei AI的应用&#xff0c;通过智能抠图、自动修复、图像生成等功能&#xff0c;用户能够快速而精确地编辑图像。②3D编辑和动画功…

蓝桥杯备赛知识点总结

一、数论 如果想要计算整除向上取整&#xff08;xy-1&#xff09;/y 或者&#xff08;x-1&#xff09;/y 1 最大公约数&#xff1a; int gcd(int a,int b){return b0?a:gcd(b,a%b); }最小公倍数&#xff1a; int lcm(int a,int b){return a/gcd(a,b)*b; } 埃氏筛法&#…

设计模式 --- 状态模式

状态模式​​是一种​​行为型设计模式​​&#xff0c;允许对象在内部状态改变时动态改变其行为​​&#xff0c;使对象的行为看起来像是改变了。该模式通过将状态逻辑拆分为独立类​​&#xff0c;消除复杂的条件分支语句&#xff0c;提升代码的可维护性和扩展性。 状态模式的…

【读者求助】如何跨行业进入招聘岗位?

文章目录 读者留言回信岗位细分1. 中介公司的招聘岗位2. 猎头专员3. 公司的招聘专员选择建议 面试建议1. 请简单介绍你过去 3 年的招聘工作经历&#xff0c;重点说下你负责的岗位类型和规模2. 你在招聘流程中最常用的渠道有哪些&#xff1f;如何评估渠道效果&#xff1f;3. 当你…

AI Agent入门指南

图片来源网络 ‌一、开箱暴击&#xff1a;你以为的"智障音箱"&#xff0c;其实是赛博世界的007‌ ‌1.1 从人工智障到智能叛逃&#xff1a;Agent进化史堪比《甄嬛传》‌ ‌青铜时代&#xff08;2006-2015&#xff09;‌ “小娜同学&#xff0c;关灯” “抱歉&…

pnpm 中 Next.js 模块无法找到问题解决

问题概述 项目在使用 pnpm 管理依赖时,出现了 “Cannot find module ‘next/link’ or its corresponding type declarations” 的错误。这是因为 pnpm 的软链接机制在某些情况下可能导致模块路径解析问题。 问题诊断 通过命令 pnpm list next 确认项目已安装 Next.js 15.2.…

vulnhub:sunset decoy

靶机下载地址https://www.vulnhub.com/entry/sunset-decoy,505/ 渗透过程 简单信息收集 nmap 192.168.56.0/24 -Pn # 确定靶机ip&#xff1a;192.168.56.121 nmap 192.168.56.121 -A -T4 # 得到开放端口22,80 在80端口得到save.zip&#xff0c;需要密码解压。 john破解压缩…

代码学习总结(一)

代码学习总结&#xff08;一&#xff09; 这个系列的博客是记录下自己学习代码的历程&#xff0c;有来自平台上的&#xff0c;有来自笔试题回忆的&#xff0c;主要基于 C 语言&#xff0c;包括题目内容&#xff0c;代码实现&#xff0c;思路&#xff0c;并会注明题目难度&…

OSPF的接口网络类型【复习篇】

OSPF在不同网络环境下默认的不同工作方式 [a3]display ospf interface g 0/0/0 # 查看ospf接口的网络类型网络类型OSPF接口的网络类型&#xff08;工作方式&#xff09;计时器BMA&#xff08;以太网&#xff09;broadcast &#xff0c;需要DR/BDR的选举hello&#xff1a;10s…