食堂采购系统源码数据库表结构与库存算法实现详解

简介: 本文详解食堂采购系统稳定性的核心:规范数据库结构(如goods、inventory、inventory_log三表协同)与强一致库存算法(乐观锁+流水驱动)。强调“库存是结果,流水是依据”,解决对账不准、超卖、负库存等顽疾,助你打造高并发、可商用的可靠系统。(239字)

很多食堂采购系统做不稳定,不是界面问题,而是底层数据结构和库存算法没设计好。
QQ20260119-152356.png

常见翻车现场你一定见过:

  • 库存经常对不上
  • 入库出库顺序混乱
  • 成本算不准
  • 多食堂同时扣库存直接变负数
  • 月底对账全靠人工补Excel

说白了:数据库结构不规范 + 库存算法太粗糙。

真正可商用的食堂采购系统源码,核心就两件事:

第一,表结构要可追溯
第二,库存算法要强一致

下面我用一套可直接落地的设计方案,把关键实现从表结构到代码完整拆开讲清楚。

一、核心业务流程梳理

先统一一个标准流程:

采购申请 → 采购单 → 入库 → 库存累加
领料/消耗 → 出库 → 库存扣减
盘点 → 差异调整
月底 → 成本核算 + 对账

所以数据库至少要支撑:

  • 供应商管理
  • 商品管理
  • 仓库管理
  • 采购入库
  • 出库领料
  • 实时库存
  • 库存流水

记住一句话:

库存 = 汇总结果
流水 = 真正依据

库存表只是“缓存”,库存流水才是“真相”。

二、核心数据库表结构设计

技术栈示例:

SpringBoot + MySQL + MyBatis

1 商品表 goods

CREATE TABLE goods (
  id BIGINT PRIMARY KEY AUTO_INCREMENT,
  name VARCHAR(100) NOT NULL,
  category_id BIGINT,
  unit VARCHAR(20),
  spec VARCHAR(100),
  enabled TINYINT DEFAULT 1,
  created_at DATETIME
);

作用:基础物料信息

示例:

  • 大米 50kg/袋
  • 鸡蛋 30枚/箱

2 供应商表 supplier

CREATE TABLE supplier (
  id BIGINT PRIMARY KEY AUTO_INCREMENT,
  name VARCHAR(200),
  contact VARCHAR(50),
  phone VARCHAR(20),
  status TINYINT DEFAULT 1
);

3 仓库表 warehouse

CREATE TABLE warehouse (
  id BIGINT PRIMARY KEY AUTO_INCREMENT,
  name VARCHAR(100),
  location VARCHAR(200)
);

支持:

  • 主仓
  • 冷藏仓
  • 分校区仓库

4 库存表 inventory(实时库存)

高频查询表

CREATE TABLE inventory (
  id BIGINT PRIMARY KEY AUTO_INCREMENT,
  goods_id BIGINT,
  warehouse_id BIGINT,
  quantity DECIMAL(10,2) DEFAULT 0,
  amount DECIMAL(12,2) DEFAULT 0,
  version INT DEFAULT 0,
  UNIQUE KEY uk_goods_wh(goods_id, warehouse_id)
);

关键字段:

  • quantity 当前数量
  • amount 总成本
  • version 乐观锁

5 库存流水表 inventory_log(核心)

这是最重要的一张表

CREATE TABLE inventory_log (
  id BIGINT PRIMARY KEY AUTO_INCREMENT,
  goods_id BIGINT,
  warehouse_id BIGINT,
  type VARCHAR(20),
  quantity DECIMAL(10,2),
  price DECIMAL(10,2),
  amount DECIMAL(12,2),
  ref_no VARCHAR(50),
  created_at DATETIME
);

type:

  • IN 入库
  • OUT 出库
  • ADJUST 盘点调整

所有库存变化必须写这张表。
QQ20250910-114722.png

三、库存算法设计思路

很多人直接:

update inventory set quantity = quantity - 10

这种做法必出事故。

正确思路:

库存变更三步走:

① 写库存流水
② 扣减库存(带锁)
③ 校验结果

四、入库算法实现(加库存)

Service 实现

@Transactional
public void stockIn(Long goodsId, Long warehouseId,
                    BigDecimal qty, BigDecimal price) {
   

    BigDecimal amount = qty.multiply(price);

    // 1 写流水
    inventoryLogMapper.insert(new InventoryLog(
            goodsId, warehouseId, "IN", qty, price, amount
    ));

    // 2 更新库存
    inventoryMapper.addStock(goodsId, warehouseId, qty, amount);
}

Mapper SQL

UPDATE inventory
SET quantity = quantity + #{
   qty},
    amount = amount + #{
   amount},
    version = version + 1
WHERE goods_id = #{
   goodsId}
AND warehouse_id = #{
   warehouseId};

五、出库算法实现(防止超卖)

重点来了。

出库一定要防:

  • 并发扣减
  • 库存负数

推荐方案:

乐观锁 + 条件扣减

核心SQL

UPDATE inventory
SET quantity = quantity - #{
   qty},
    amount = amount - #{
   amount},
    version = version + 1
WHERE goods_id = #{
   goodsId}
AND warehouse_id = #{
   warehouseId}
AND quantity >= #{
   qty}
AND version = #{
   version};

如果影响行数为 0 → 扣减失败。

Java实现

@Transactional
public void stockOut(Long goodsId, Long warehouseId,
                     BigDecimal qty) {
   

    Inventory inv = inventoryMapper.select(goodsId, warehouseId);

    if (inv.getQuantity().compareTo(qty) < 0) {
   
        throw new RuntimeException("库存不足");
    }

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

    BigDecimal amount = avgPrice.multiply(qty);

    int rows = inventoryMapper.reduceStock(
            goodsId, warehouseId, qty, amount, inv.getVersion());

    if (rows == 0) {
   
        throw new RuntimeException("库存并发冲突,请重试");
    }

    inventoryLogMapper.insert(
            new InventoryLog(goodsId, warehouseId, "OUT", qty, avgPrice, amount)
    );
}

六、成本算法(加权平均法)

食堂场景推荐:

加权平均法

原因:

  • 计算简单
  • 实时成本准确
  • 不用复杂批次管理

公式:

新平均价 = (旧金额 + 入库金额) ÷ (旧数量 + 入库数量)

SQL 示例:

amount / quantity

直接算即可。

七、高并发优化建议

如果是多校区或集团食堂,订单并发高时:

必须加:

1 分库分表(按仓库拆)
2 Redis库存缓存
3 批量入库写入
4 异步流水日志

否则库存表会成为瓶颈。
QQ20260119-152406.png

八、总结一句实战经验

如果你正在做食堂采购系统源码,记住这三条铁律:

库存只查 inventory
对账只查 inventory_log
任何库存变化必须走事务

这样系统跑几年都不会乱。

真正商用级系统,拼的不是功能多,而是:

数据稳定 + 算法可靠 + 并发安全

底层打牢,上层再怎么扩展都不怕。

相关文章
|
3月前
|
NoSQL 前端开发 数据挖掘
私域直播系统源码架构解析:从开播到成交的完整链路设计
本文深度解析私域直播系统源码级实现,涵盖推流鉴权、实时互动(WebSocket+Redis)、商品挂载、秒级下单、支付闭环及用户标签沉淀等全链路架构。强调技术可控、数据归属与业务可扩展性,助力企业构建稳定、自主、可复用的私域直播闭环。(239字)
|
2月前
|
消息中间件 NoSQL 算法
开源跑腿系统开发看似省钱,其实是技术债的开始?
创业者常问:“有开源跑腿系统吗?改改就能上线?”看似省钱,实则埋雷。多数开源项目缺并发控制、智能调度、分布式架构等核心能力,后期维护成本远超开发成本。真正关键不是“有没有代码”,而是你是否有技术掌控力——能否重构、修Bug、升级架构。开源是加速器,不是救命稻草。(239字)
|
2月前
|
消息中间件 算法 调度
外卖系统开发真的赚钱吗?90%的创业者可能选错了方向
外卖系统开发≠印钞机!90%创业者败在方向错误而非技术。本文直击本质:赚钱靠的是“商业模型+调度算法+生态构建”,而非简单CRUD。从高并发架构、智能派单到垂直场景切入,拆解真正可持续的盈利路径。(239字)
|
13天前
|
存储 小程序 前端开发
私域直播带货小程序怎么搭建?一套完整流程讲清楚
本文详解私域直播带货小程序搭建全流程:涵盖需求分析、技术选型、前后端架构设计,及直播播放、商品管理、微信支付、分销裂变、消息推送等核心模块,并提供关键代码示例与高并发、库存同步等实战注意事项。(239字)
|
20天前
|
存储 搜索推荐 数据安全/隐私保护
大健康私域直播系统搭建趋势:线上问诊与直播带动的模式升级
在大健康数字化加速背景下,单一问诊或电商模式难以为继。大健康私域直播系统通过“直播+问诊+服务+商品”融合,重构流量逻辑与技术架构,实现用户沉淀、信任建立与持续转化,打造闭环运营的业务操作系统。(239字)
|
27天前
|
存储 缓存 数据挖掘
企业内训系统搭建课程、考试与数据分析模块设计思路
本文详解企业内训系统底层架构设计,聚焦课程、考试、学习轨迹与数据分析四大模块,强调“结构决定价值”:通过三层课程模型、可追溯学习记录、题库复用考试结构及预聚合统计表等实践,确保系统支撑精细化运营与长期数据驱动决策。(239字)
|
3月前
|
缓存 前端开发 NoSQL
知识付费系统开发核心架构拆解:从内容管理到支付闭环实现
本文直击知识付费平台核心痛点,摒弃华而不实的前端包装,从技术架构底层拆解内容管理、权限控制、订单支付、分账结算等关键模块。详解分层/微服务架构设计、数据库建模、鉴权播放、幂等回调、缓存优化等实战方案,强调“内容安全、交易稳定、权限精确、可扩展升级”四大目标,助你打造高可用、可持续迭代的硬核系统。(239字)
|
5月前
|
前端开发 安全 JavaScript
网站代码 网站源代码 网页源代码 网页代码网站
本文深入解析网站源代码与网页源代码的核心概念及区别,阐述其作为互联网技术基石的关键作用。通过剖析PageAdmin等典型源码案例,揭示源代码在技术学习、网站优化、安全维护等方面的核心价值,并探讨如何高效利用代码网站资源进行创新开发。文章强调在尊重版权的前提下,开发者可借助源码资源提升能力,推动网页技术持续发展。
1749 10
|
5月前
|
缓存 NoSQL 关系型数据库
优惠券功能设计与实现
本文从底层逻辑出发,全面拆解优惠券功能的核心设计要点,结合JDK17、MyBatis-Plus、MySQL8.0等最新稳定技术栈,提供全量可编译运行的实现代码,帮助开发者快速掌握从需求分析到落地部署的完整流程。
570 4