食堂采购系统源码库存扣减算法与并发控制实现详解
做食堂采购系统真正难的从来不是页面也不是流程。而是两个字库存。很多团队一开始都觉得库存扣减很简单update inventory set quantity quantity - 10;上线一周后就开始出问题库存变负数多人同时领料数据错乱成本算不准对账永远对不上高峰期直接超卖说句实在话只要库存算法没设计好这套系统就一定跑不久。食堂场景有个特点早上集中入库中午集中出库多窗口同时领料并发非常高这本质就是一个「高并发扣库存」系统。下面我从实战角度把一套能商用落地的库存扣减方案完整拆开讲清楚。技术栈示例SpringBoot MySQL MyBatis Redis一、先搞清楚库存的本质模型很多人一上来就写扣减逻辑这是顺序错了。库存正确模型应该是库存表 当前结果流水表 真实依据必须是有流水 → 才能变库存而不是直接改库存。推荐表结构1 库存主表 inventoryCREATETABLEinventory(idBIGINTPRIMARYKEYAUTO_INCREMENT,goods_idBIGINTNOTNULL,warehouse_idBIGINTNOTNULL,quantityDECIMAL(10,2)DEFAULT0,amountDECIMAL(12,2)DEFAULT0,versionINTDEFAULT0,UNIQUEKEYuk_goods_wh(goods_id,warehouse_id));关键字段quantity 当前库存amount 库存总成本version 乐观锁2 库存流水表 inventory_logCREATETABLEinventory_log(idBIGINTPRIMARYKEYAUTO_INCREMENT,goods_idBIGINT,warehouse_idBIGINT,typeVARCHAR(20),quantityDECIMAL(10,2),priceDECIMAL(10,2),amountDECIMAL(12,2),created_atDATETIME);所有变化都必须记录。这是后期对账的唯一依据。二、最容易踩坑的 3 种错误写法错误写法一直接扣减updateinventorysetquantityquantity-5;问题无并发保护多线程同时扣 → 负数直接淘汰。错误写法二先查再扣Inventoryinvselect();if(inv.getQuantity()5){update();}问题并发时两个线程都读到 10都能扣。结果变 -5。这叫读写分离导致超卖错误写法三只加事务很多人以为Transactional 就安全了。错。事务只能保证单线程一致不能解决并发竞争。三、正确思路三层并发控制模型真正可商用方案一定是第一层数据库乐观锁第二层条件扣减第三层Redis预扣减高并发场景三层叠加才稳。四、核心方案一MySQL乐观锁扣减基础必备这是所有系统的底线方案。扣减SQL核心UPDATEinventorySETquantityquantity-#{qty},amountamount-#{amount},versionversion1WHEREgoods_id#{goodsId}ANDwarehouse_id#{warehouseId}ANDquantity#{qty}ANDversion#{version};重点quantity qty 防止负数version 防止并发覆盖影响行数 1 才成功。Java实现TransactionalpublicvoidstockOut(LonggoodsId,LongwarehouseId,BigDecimalqty){InventoryinvinventoryMapper.select(goodsId,warehouseId);if(inv.getQuantity().compareTo(qty)0){thrownewRuntimeException(库存不足);}BigDecimalavgPriceinv.getAmount().divide(inv.getQuantity(),2,RoundingMode.HALF_UP);BigDecimalamountavgPrice.multiply(qty);introwsinventoryMapper.reduceStock(goodsId,warehouseId,qty,amount,inv.getVersion());if(rows0){thrownewRuntimeException(并发冲突请重试);}inventoryLogMapper.insert(newInventoryLog(goodsId,warehouseId,OUT,qty,avgPrice,amount));}优点实现简单强一致适合中等并发缺点高并发下重试多性能下降五、核心方案二悲观锁强一致但慢如果库存极度敏感可以用SELECT*FROMinventoryWHEREgoods_id?FORUPDATE;锁行再更新。问题是高并发直接阻塞吞吐量低。食堂中午高峰可能直接卡死。所以只建议小并发系统使用。六、核心方案三Redis MySQL 双层扣减高并发推荐当多窗口同时领料上百人同时出库单靠数据库扛不住。必须引入 Redis。思路是先扣 Redis再异步写 MySQLRedis Lua脚本原子扣减localstocktonumber(redis.call(get,KEYS[1]))ifstock0thenreturn-1endredis.call(decrby,KEYS[1],ARGV[1])return1保证原子性无超卖Java调用LongresultredisTemplate.execute(luaScript,Collections.singletonList(stock:goodsId),qty.toString());if(result-1){thrownewRuntimeException(库存不足);}异步落库使用 MQmqProducer.send(newStockMessage(goodsId,qty));消费者再更新数据库。优点极高并发抗压能力强缺点最终一致性实现复杂适合多食堂 集团化 上千并发场景。七、成本算法实现食堂最佳实践食堂不需要复杂批次。推荐加权平均法公式平均价amount/quantity实现BigDecimalavgPriceinv.getAmount().divide(inv.getQuantity(),2,RoundingMode.HALF_UP);简单、稳定、易对账。八、实战选型建议给你一句很现实的选型建议小学校直接 MySQL 乐观锁中型学校乐观锁 索引优化集团/多校区Redis MQ MySQL别一上来就搞复杂架构。技术是为业务服务不是炫技。九、最后的经验总结做食堂采购系统源码这三条是底线原则第一库存只改一张表必须带锁第二所有变更必须写流水第三绝不允许负库存只要守住这三条系统稳定性至少提升一个量级。库存做好了这套系统才算真正可商用。

相关新闻

C语言复合运算符在嵌入式系统中的硬件映射与原子性实践

C语言复合运算符在嵌入式系统中的硬件映射与原子性实践

1. C语言复合运算符:从语法表达到工程实践的深度解析在嵌入式C语言开发中,复合运算符(Compound Assignment Operators)常被初学者视为“语法糖”,仅用于代码缩写。但深入工程实践会发现,其设计逻辑紧密耦合…

2026/7/4 16:43:56 阅读更多 →
基于HY-Motion 1.0的Dify平台应用开发

基于HY-Motion 1.0的Dify平台应用开发

基于HY-Motion 1.0的Dify平台应用开发 1. 为什么要在Dify上集成HY-Motion 1.0 想象一下这样的场景:游戏工作室的策划人员在下午三点提交了一个需求——“需要一个角色在雨中奔跑时突然滑倒,然后笑着爬起来拍打裤子上的泥”。传统流程里,这个…

2026/7/4 23:41:16 阅读更多 →
灵感画廊应用场景:电商设计师用‘影院余晖’预设3分钟生成节日主图系列

灵感画廊应用场景:电商设计师用‘影院余晖’预设3分钟生成节日主图系列

灵感画廊应用场景:电商设计师用‘影院余晖’预设3分钟生成节日主图系列 1. 为什么电商设计师需要“影院余晖”这一秒级灵感开关 你有没有遇到过这样的场景: 凌晨一点,双十二大促海报 deadline 还剩6小时,运营甩来一句&#xff1…

2026/7/4 14:53:03 阅读更多 →

最新新闻

如何从‘能聊天’升级到‘让别人愿意主动找你聊’的系统?

如何从‘能聊天’升级到‘让别人愿意主动找你聊’的系统?

一、第一刀:为什么大多数人只能“能聊天”,不能“被找聊”? 因为他们停留在:被动对话系统✔ 特征: 别人发起你回应你维持但不会“积累吸引力”👉 本质:只是“对话节点”,不是“对话源…

2026/7/4 23:41:22 阅读更多 →
基于Playwright与MCP协议实现浏览器自动化与手动操作协同

基于Playwright与MCP协议实现浏览器自动化与手动操作协同

1. 项目概述:当自动化脚本遇上你的手动操作在浏览器自动化测试和爬虫开发的日常里,我们常常面临一个尴尬的割裂:一边是精心编写的Playwright脚本,在无头模式下高效、稳定地执行任务;另一边,则是我们自己手动…

2026/7/4 23:39:21 阅读更多 →
通过COM组件在Web上实现Kinect骨骼追踪、声控截屏保存的功能

通过COM组件在Web上实现Kinect骨骼追踪、声控截屏保存的功能

具体实现 第一部分 ActiveX插件的实现 1) 创建一个新的解决方案,叫做MyFirstKinect。 2)接着创建一个Windows窗体控件库,用于做ActiveX的插件,项目叫做MyFirstKinectControl 3)在MyFirstKinectControl项目…

2026/7/4 23:39:21 阅读更多 →
Coze平台AI Agent开发实战与优化技巧

Coze平台AI Agent开发实战与优化技巧

1. Coze平台与AI Agent开发概述作为一名长期从事AI应用开发的工程师,我最近深度体验了Coze平台在AI Agent开发中的实际表现。这个由字节跳动推出的开发平台确实为不同技术背景的用户提供了一种全新的AI应用构建方式。与传统开发模式相比,Coze最显著的特点…

2026/7/4 23:39:21 阅读更多 →
机器学习模型线上稳定性实战:特征一致性、数据漂移与推理容错

机器学习模型线上稳定性实战:特征一致性、数据漂移与推理容错

1. 这不是“跑通模型”就完事的课——它讲的是模型怎么在真实业务里活下来“From Notebook to Production: Running ML in the Real World (Part 4)”这个标题,光看前半句,很多人会下意识划走:又一个讲MLOps流程的泛泛而谈?但关键…

2026/7/4 23:37:20 阅读更多 →
【Java课程设计/毕业设计】花园设计案例展示与预约咨询管理系统的设计与实现 景观设计师工作调度管理系统【附源码、数据库、万字文档】

【Java课程设计/毕业设计】花园设计案例展示与预约咨询管理系统的设计与实现 景观设计师工作调度管理系统【附源码、数据库、万字文档】

博主介绍:✌️码农一枚 ,专注于大学生项目实战开发、讲解和毕业🚢文撰写修改等。全栈领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围:&am…

2026/7/4 23:35:18 阅读更多 →

日新闻

Memcached 1.6.43 发布:关键安全修复版本,多项问题得到解决

Memcached 1.6.43 发布:关键安全修复版本,多项问题得到解决

Memcached 1.6.43 正式发布,这是一个关键的安全修复版本,修复了多个方面的问题,还对部分功能进行了优化。 安全修复亮点 此次发布在安全修复上表现突出。binprot 避免了项目引用计数溢出,mcmc 因安全问题提升了上游版本号&#xf…

2026/7/4 0:04:29 阅读更多 →
终极指南:使用HMCL启动器跨平台畅玩Minecraft的完整解决方案

终极指南:使用HMCL启动器跨平台畅玩Minecraft的完整解决方案

终极指南:使用HMCL启动器跨平台畅玩Minecraft的完整解决方案 【免费下载链接】HMCL A Minecraft Launcher which is multi-functional, cross-platform and popular 项目地址: https://gitcode.com/gh_mirrors/hm/HMCL HMCL(Hello Minecraft! Lau…

2026/7/4 0:06:29 阅读更多 →
KMX63与PIC18F66K40在嵌入式HMI中的硬件协同与低功耗设计

KMX63与PIC18F66K40在嵌入式HMI中的硬件协同与低功耗设计

1. KMX63与PIC18F66K40的硬件协同架构解析KMX63作为一款三轴加速度计和磁力计组合传感器,与PIC18F66K40微控制器的搭配堪称嵌入式HMI开发的黄金组合。这套硬件组合的核心优势在于KMX63提供的高精度运动感知能力与PIC18F66K40强大的信号处理能力形成了完美互补。KMX6…

2026/7/4 0:06:29 阅读更多 →

周新闻

月新闻