订单主表用 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且带符号(支持临时负数调试),但业务逻辑里绝不允许负库存出库——扣减前校验比锁更前置、更轻量。
