mysql在餐饮管理系统中的订单与菜品数据存储

来源:这里教程网 时间:2026-02-28 20:41:33 作者:

订单主表用
orders
还是
order_master
?别用
order

MySQL 里

order
是保留字(
ORDER BY
),直接建表会报错
ERROR 1064 (42000)
。实际项目中见过三次因这命名导致初始化失败。推荐用
orders
——简洁、通用、ORM 友好;
order_master
虽语义清晰,但冗余,且和关联表
order_items
不对称。

字段设计要预留扩展: -

status
TINYINT
ENUM('pending','confirmed','canceled','completed')
,别用字符串,避免拼写不一致 -
created_at
updated_at
必须有,餐饮场景常需查“10 分钟内未确认的订单” - 外键
customer_id
建议允许
NULL
(堂食匿名下单常见)

order_items
表必须拆分菜品与规格,不能只存
menu_id

用户点的是“宫保鸡丁(微辣,加花生)”,不是抽象的“宫保鸡丁”。如果

order_items
只记
menu_id
,结账后无法还原当时选择——辣度、配菜、是否去葱等都丢了。

正确结构包含: -

menu_id
(指向菜品主表) -
specification
字段存 JSON,如
{"spicy":"mild","add":"peanuts"}
;或更规范地建独立
item_specifications
表 -
notes
字段留作自由备注(“不要香菜”“打包”) - 单价
unit_price
必须快照保存,否则菜单调价后历史订单金额对不上

菜品数据用
menus
+
menu_categories
两级,别硬塞进一个表

餐厅菜单常按“凉菜/热菜/酒水/套餐”分类,且分类可能动态增减(比如夏天加“冰饮”类)。若把分类名直接存在

menus.category_name
字段,会导致: - 修改分类名要全表
UPDATE
- 无法设置分类排序(“酒水”总得排最后) - 不能给分类设启用/禁用状态(下架某类但保留菜品)

推荐做法: -

menu_categories
表含
id
name
sort_order
is_active
-
menus
表用
category_id
关联,加
is_available
控制单个菜品上下架 - 查询某分类下可用菜品时,两表
JOIN
+
WHERE category.is_active = 1 AND menu.is_available = 1

高并发下单时,
SELECT ... FOR UPDATE
锁哪一行?别锁整张表

库存扣减场景(如“麻婆豆腐只剩 2 份”),多个服务员同时点单,必须防超卖。错误做法:

SELECT stock FROM menus WHERE id = 123
后再
UPDATE
——中间有竞态窗口。

正确姿势: - 在事务中执行

SELECT stock FROM menus WHERE id = 123 FOR UPDATE
,锁住该行 - 立即判断
stock >= required_qty
,不满足则
ROLLBACK
- 满足则
UPDATE menus SET stock = stock - ? WHERE id = 123
- 注意:
FOR UPDATE
只在事务内有效,且索引必须覆盖
WHERE
条件(
id
主键天然支持) - 切勿在
orders
表上加锁——那会阻塞所有新订单,而库存锁只影响同一菜品

START TRANSACTION;
SELECT stock FROM menus WHERE id = 123 FOR UPDATE;
-- 应用层判断库存是否充足
UPDATE menus SET stock = stock - 1 WHERE id = 123;
INSERT INTO order_items (order_id, menu_id, quantity, unit_price) VALUES (456, 123, 1, 28.00);
COMMIT;

最易被忽略的一点:菜品库存字段

stock
必须是
INT
且带符号(支持临时负数调试),但业务逻辑里绝不允许负库存出库——扣减前校验比锁更前置、更轻量。

相关推荐