news 2026/5/15 3:14:32

食堂采购系统源码库存扣减算法与并发控制实现详解

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
食堂采购系统源码库存扣减算法与并发控制实现详解

做食堂采购系统,真正难的从来不是页面,也不是流程。

而是两个字:库存。

很多团队一开始都觉得库存扣减很简单:

update inventory set quantity = quantity - 10;

上线一周后就开始出问题:

  • 库存变负数
  • 多人同时领料数据错乱
  • 成本算不准
  • 对账永远对不上
  • 高峰期直接超卖

说句实在话:

只要库存算法没设计好,这套系统就一定跑不久。

食堂场景有个特点:

  • 早上集中入库
  • 中午集中出库
  • 多窗口同时领料
  • 并发非常高

这本质就是一个「高并发扣库存」系统。

下面我从实战角度,把一套能商用落地的库存扣减方案完整拆开讲清楚。

技术栈示例:

SpringBoot + MySQL + MyBatis + Redis

一、先搞清楚库存的本质模型

很多人一上来就写扣减逻辑,这是顺序错了。

库存正确模型应该是:

库存表 = 当前结果
流水表 = 真实依据

必须是:

有流水 → 才能变库存

而不是直接改库存。

推荐表结构

1 库存主表 inventory

CREATETABLEinventory(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_log

CREATETABLEinventory_log(idBIGINTPRIMARYKEYAUTO_INCREMENT,goods_idBIGINT,warehouse_idBIGINT,typeVARCHAR(20),quantityDECIMAL(10,2),priceDECIMAL(10,2),amountDECIMAL(12,2),created_atDATETIME);

所有变化都必须记录。

这是后期对账的唯一依据。

二、最容易踩坑的 3 种错误写法

错误写法一:直接扣减

updateinventorysetquantity=quantity-5;

问题:

  • 无并发保护
  • 多线程同时扣 → 负数

直接淘汰。

错误写法二:先查再扣

Inventoryinv=select();if(inv.getQuantity()>=5){update();}

问题:

并发时两个线程都读到 10,都能扣。

结果变 -5。

这叫:读写分离导致超卖

错误写法三:只加事务

很多人以为:

@Transactional 就安全了。

错。

事务只能保证单线程一致,不能解决并发竞争。

三、正确思路:三层并发控制模型

真正可商用方案一定是:

第一层:数据库乐观锁
第二层:条件扣减
第三层:Redis预扣减(高并发场景)

三层叠加,才稳。

四、核心方案一:MySQL乐观锁扣减(基础必备)

这是所有系统的底线方案。

扣减SQL(核心)

UPDATEinventorySETquantity=quantity-#{qty},amount=amount-#{amount},version=version+1WHEREgoods_id=#{goodsId}ANDwarehouse_id=#{warehouseId}ANDquantity>=#{qty}ANDversion=#{version};

重点:

  • quantity >= qty 防止负数
  • version 防止并发覆盖

影响行数 = 1 才成功。

Java实现

@TransactionalpublicvoidstockOut(LonggoodsId,LongwarehouseId,BigDecimalqty){Inventoryinv=inventoryMapper.select(goodsId,warehouseId);if(inv.getQuantity().compareTo(qty)<0){thrownewRuntimeException("库存不足");}BigDecimalavgPrice=inv.getAmount().divide(inv.getQuantity(),2,RoundingMode.HALF_UP);BigDecimalamount=avgPrice.multiply(qty);introws=inventoryMapper.reduceStock(goodsId,warehouseId,qty,amount,inv.getVersion());if(rows==0){thrownewRuntimeException("并发冲突,请重试");}inventoryLogMapper.insert(newInventoryLog(goodsId,warehouseId,"OUT",qty,avgPrice,amount));}

优点:

  • 实现简单
  • 强一致
  • 适合中等并发

缺点:

高并发下重试多,性能下降

五、核心方案二:悲观锁(强一致但慢)

如果库存极度敏感,可以用:

SELECT*FROMinventoryWHEREgoods_id=?FORUPDATE;

锁行再更新。

问题是:

高并发直接阻塞,吞吐量低。

食堂中午高峰可能直接卡死。

所以:

只建议小并发系统使用。

六、核心方案三:Redis + MySQL 双层扣减(高并发推荐)

当:

  • 多窗口同时领料
  • 上百人同时出库

单靠数据库扛不住。

必须引入 Redis。

思路是:

先扣 Redis
再异步写 MySQL

Redis Lua脚本(原子扣减)

localstock=tonumber(redis.call('get',KEYS[1]))ifstock<=0thenreturn-1endredis.call('decrby',KEYS[1],ARGV[1])return1

保证:

  • 原子性
  • 无超卖

Java调用

Longresult=redisTemplate.execute(luaScript,Collections.singletonList("stock:"+goodsId),qty.toString());if(result==-1){thrownewRuntimeException("库存不足");}

异步落库

使用 MQ:

mqProducer.send(newStockMessage(goodsId,qty));

消费者再更新数据库。

优点:

  • 极高并发
  • 抗压能力强

缺点:

  • 最终一致性
  • 实现复杂

适合:

多食堂 + 集团化 + 上千并发场景。

七、成本算法实现(食堂最佳实践)

食堂不需要复杂批次。

推荐:

加权平均法

公式:

平均价=amount/quantity

实现:

BigDecimalavgPrice=inv.getAmount().divide(inv.getQuantity(),2,RoundingMode.HALF_UP);

简单、稳定、易对账。

八、实战选型建议

给你一句很现实的选型建议:

小学校
直接 MySQL 乐观锁

中型学校
乐观锁 + 索引优化

集团/多校区
Redis + MQ + MySQL

别一上来就搞复杂架构。

技术是为业务服务,不是炫技。

九、最后的经验总结

做食堂采购系统源码,这三条是底线原则:

第一
库存只改一张表,必须带锁

第二
所有变更必须写流水

第三
绝不允许负库存

只要守住这三条,系统稳定性至少提升一个量级。

库存做好了,这套系统才算真正可商用。

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

7个专业技巧:解锁NVIDIA显卡隐藏性能的终极指南

7个专业技巧&#xff1a;解锁NVIDIA显卡隐藏性能的终极指南 【免费下载链接】nvidiaProfileInspector 项目地址: https://gitcode.com/gh_mirrors/nv/nvidiaProfileInspector 作为PC游戏玩家&#xff0c;你是否经常遇到画面撕裂、输入延迟过高或游戏卡顿等问题&#xf…

作者头像 李华
网站建设 2026/5/1 9:52:31

XUnity.AutoTranslator:Unity游戏实时翻译解决方案

XUnity.AutoTranslator&#xff1a;Unity游戏实时翻译解决方案 【免费下载链接】XUnity.AutoTranslator 项目地址: https://gitcode.com/gh_mirrors/xu/XUnity.AutoTranslator 还在为外语游戏剧情看不懂而抓狂&#xff1f;面对满屏英文界面不知如何操作&#xff1f;XUn…

作者头像 李华
网站建设 2026/5/15 3:14:03

Chord视频分析工具效果实测:300+真实视频样本定位准确率统计

Chord视频分析工具效果实测&#xff1a;300真实视频样本定位准确率统计 1. 为什么需要一款真正“看得懂”视频的本地工具&#xff1f; 你有没有遇到过这样的情况&#xff1a;手头有一段监控录像&#xff0c;想快速确认“穿红衣服的人是什么时候出现在画面左下角的”&#xff…

作者头像 李华
网站建设 2026/5/15 3:13:05

3个秘诀让你精通开源虚拟手柄驱动:从入门到专业的游戏控制革新

3个秘诀让你精通开源虚拟手柄驱动&#xff1a;从入门到专业的游戏控制革新 【免费下载链接】ViGEmBus 项目地址: https://gitcode.com/gh_mirrors/vig/ViGEmBus 虚拟手柄驱动是解决非标准游戏控制器兼容性问题的核心方案&#xff0c;通过游戏控制器模拟技术&#xff0c…

作者头像 李华
网站建设 2026/5/1 17:09:49

Face3D.ai Pro惊艳效果展示:单图重建的4K UV贴图细节放大对比

Face3D.ai Pro惊艳效果展示&#xff1a;单图重建的4K UV贴图细节放大对比 1. 这不是“修图”&#xff0c;是把一张照片“解剖”成三维世界 你有没有试过&#xff0c;只给一张正面自拍照&#xff0c;就让电脑自动还原出你整张脸的立体结构&#xff1f;不是简单加个滤镜&#x…

作者头像 李华
网站建设 2026/5/8 6:48:53

【R文本挖掘配置黄金标准】:20年专家亲授5大避坑指南与3步极速部署法

第一章&#xff1a;R文本挖掘配置黄金标准总览构建稳健、可复现的R文本挖掘环境&#xff0c;关键在于统一依赖管理、版本锁定与跨平台兼容性保障。黄金标准并非追求最新版本&#xff0c;而是强调确定性、隔离性与可审计性——即每次执行相同代码&#xff0c;无论操作系统或R版本…

作者头像 李华