简介
本文件面向DouPHP电商系统的“商品SKU与库存管理”模块,聚焦数据模型、SKU编码规则、多规格组合、库存扣减机制、库存预警、价格计算、库存同步、批次管理、搜索优化、批量操作、库存调拨以及高并发一致性保障等主题。文档基于仓库中产品模型、订单状态机与升级脚本的实际实现进行梳理,给出可落地的表结构设计建议与业务流程图,帮助开发者构建稳定、可扩展的SKU与库存体系。
项目结构
围绕SKU与库存的核心代码集中在以下位置:
- 产品模型:后台与前台分别提供产品数据的读写封装,包含stock、sales、price、promote_price、level_price、model等字段的映射与格式化。
- 订单状态机:在订单付款后触发库存扣减与销售计数更新,并维护库存锁定标记。
- 升级脚本:定义product表的扩展字段(如stock、model、promote*、status、slug、operator*等)及索引。
- 售后与订单项:通过order_item关联具体商品,用于售后、评价、统计等场景。
graph TB
A["产品模型(后台)"] --> B["产品模型(前台)"]
C["订单状态机"] --> D["产品表(product)"]
E["结账服务"] --> F["订单项(order_item)"]
F --> D
G["升级脚本"] --> D
核心组件
- 产品模型(后台/前台):负责product表字段的读写、格式化与查询过滤,包含stock、sales、price、promote_price、level_price、model、status、slug等。
- 订单状态机:在订单进入已支付状态时,按订单项对product表执行库存扣减与销售计数累加,并清理库存锁定标记。
- 结账服务:在创建订单时根据配置决定是否设置库存锁定标志,为后续扣减提供前置条件。
- 升级脚本:确保product表具备必要的库存与促销字段,并建立必要索引以支持查询与权限隔离。
架构总览
下图展示从下单到库存扣减的关键流程,以及产品模型与订单状态机的交互关系。
sequenceDiagram
participant U as "用户"
participant OCS as "结账服务"
participant ORD as "订单状态机"
participant DB as "数据库"
participant PRD as "产品表(product)"
U->>OCS : 提交订单
OCS->>DB : 写入订单(order)
OCS->>DB : 写入订单项(order_item)
Note over OCS,DB : 根据配置设置库存锁定标志(stock_lock)
OCS-->>U : 返回订单号
U->>ORD : 支付完成回调
ORD->>DB : 更新订单状态为已支付
ORD->>DB : 遍历order_item并扣减product.stock、累加product.sales
ORD->>DB : 清空order_item.stock_lock
ORD-->>U : 返回支付成功
详细组件分析
产品模型与SKU数据模型
- 表名与主键:product表,主键id自增。
- SKU相关字段:
- stock:当前可售库存(整型)。
- sales:累计销售数量(整型)。
- price:基础售价(数值)。
- promote_price:促销价(数值),配合促销起止时间字段使用。
- level_price:等级价格(字符串,通常存储JSON或序列化后的会员等级价格映射)。
- model:型号串(唯一性由生成逻辑保证),可作为SKU编码的基础。
- status:上架状态(1=上架)。
- slug:URL友好标识,带索引便于快速检索。
- operator_type/operator_id:创建者类型与ID,用于工作台权限隔离。
- 多语言与附件:name/title/content/description等多语言字段;image为附件编号,列表页会预热缩略图与相册首图。
- 查询能力:支持按标题模糊筛选、分类筛选、品牌筛选、归档时间窗筛选、默认排序等。
classDiagram
class ProductModel {
+int id
+string title
+string slug
+decimal price
+decimal promote_price
+string level_price
+int stock
+int sales
+string model
+tinyint status
+string operator_type
+int operator_id
+datetime created_at
+category()
+brand()
}
多规格组合算法与SKU编码规则
- 规格维度:颜色、尺码、材质等属性值组合形成变体。
- 编码策略:
- 以product.model作为SKU基础编码,结合规格属性哈希或有序拼接生成唯一SKU码。
- 建议在product表中增加sku_code字段(字符串,唯一索引),并在入库前校验唯一性。
- 多规格组合可通过“属性键值对”的规范化表示(如JSON)存储于product.level_price或独立规格表,便于前端渲染与价格计算。
- 价格计算:
- 基础价price作为基准,促销价promote_price在有效期内覆盖显示价。
- 会员等级价level_price按登录用户等级动态选择,未登录则回退到基础价或促销价。
- 库存绑定:
- 每个SKU对应一个product记录,stock为该SKU可售库存。
- 若采用共享库存策略,可在父级product聚合stock,子级SKU仅记录配额。
flowchart TD
Start(["开始"]) --> CollectAttrs["收集规格属性<br/>颜色/尺码/材质..."]
CollectAttrs --> Normalize["规范化属性键值对"]
Normalize --> GenCode["生成SKU编码<br/>model+属性哈希"]
GenCode --> CheckUnique{"是否唯一?"}
CheckUnique -- 否 --> Retry["重新生成或冲突处理"]
CheckUnique -- 是 --> Save["保存至product表<br/>设置stock/price/level_price"]
Save --> End(["结束"])
库存扣减机制与库存同步
- 触发时机:订单状态变更为“已支付”时,系统遍历该订单的订单项,对product表执行:
- stock = stock - item_number
- sales = sales + item_number
- 库存锁定:
- 下单时可根据配置设置order_item.stock_lock标志,支付成功后清零,避免重复扣减。
- 幂等与一致性:
- 扣减在同一事务内完成,异常时回滚。
- 事件派发在事务提交后进行,下游联动失败不影响订单状态。
sequenceDiagram
participant ORD as "订单状态机"
participant DB as "数据库"
participant PRD as "产品表(product)"
participant OI as "订单项(order_item)"
ORD->>DB : 开启事务
ORD->>OI : 读取order_item列表
loop 遍历订单项
ORD->>PRD : UPDATE product SET stock=stock-item_number, sales=sales+item_number WHERE id=item_id
end
ORD->>OI : UPDATE order_item SET stock_lock=0
ORD->>DB : 提交事务
库存预警与批次管理
- 库存预警:
- 建议在product表增加low_stock阈值字段(如min_stock),在库存变更时检查并触发告警(站内信/短信/邮件)。
- 可结合定时任务扫描低库存SKU,推送补货提醒。
- 批次管理:
- 引入批次表(如product_batch),记录入库批次、生产日期、有效期、供应商、数量等。
- 出库时按先进先出(FIFO)或指定批次策略扣减批次库存,并与product.stock保持汇总一致。
- 批次与SKU一对一或多对一关系,支持批次追溯与召回。
搜索优化与批量操作
- 搜索优化:
- 利用slug字段索引提升URL友好路径检索效率。
- 针对title、keywords、description等字段建立全文索引或使用搜索引擎(如Elasticsearch)以提升检索性能。
- 列表页使用prefetchers预热附件、多语言与缩略图,减少N+1查询。
- 批量操作:
- 后台支持批量更新stock、price、promote_price等字段,注意分批提交与事务边界控制。
- 批量导入SKU时,需校验model/sku_code唯一性与规格组合合法性。
库存调拨与高级特性
- 库存调拨:
- 在多仓或多门店场景下,引入warehouse_stock表记录各仓库SKU库存,product.stock为全局汇总。
- 调拨单记录源仓、目标仓、SKU、数量、状态,调拨完成后分步扣减源仓、增加目标仓,并同步product.stock。
- 高级特性:
- 预售与预约:预留库存与真实库存分离,预购阶段仅占用预留量,发货时转为实际扣减。
- 虚拟库存:对于数字商品或服务类,stock可为负数表示可超卖,配合风控策略控制风险。
- 库存快照:在订单创建时记录snapshot(含price、stock、level_price等),用于结算与审计。
依赖关系分析
- 产品模型依赖product表字段,受升级脚本影响。
- 订单状态机依赖order与order_item表,并在付款后对product表进行写操作。
- 结账服务在订单创建阶段设置库存锁定标志,影响后续扣减流程。
- 售后与订单项读取order_item,用于展示与权限判断。
graph LR
Upgrade["升级脚本"] --> Product["product表"]
AdminModel["后台产品模型"] --> Product
FrontModel["前台产品模型"] --> Product
Checkout["结账服务"] --> OrderItem["order_item表"]
OrderState["订单状态机"] --> OrderItem
OrderState --> Product
性能考虑
- 索引优化:
- 为product.slug建立索引,提升URL路由与列表筛选性能。
- 为operator_type、operator_id建立复合索引,支持工作台权限隔离查询。
- 查询预热:
- 使用prefetchers批量预热附件、多语言与缩略图,减少N+1查询。
- 事务与锁:
- 库存扣减在事务内执行,避免并发下的不一致。
- 在高并发场景下,可结合行级锁(FOR UPDATE)或分布式锁防止超卖。
- 异步化:
- 将非关键路径(如积分发放、分销奖励、等级升级)移至事务外异步处理,降低主流程延迟。
故障排查指南
- 库存未扣减:
- 检查订单状态是否为“已支付”,确认订单状态机是否正确触发。
- 核对order_item.stock_lock是否已清零,避免重复扣减或阻塞。
- 库存不一致:
- 查看product.stock与order_item.item_number的累计差异,定位异常订单。
- 检查是否有外部系统直接修改product.stock,导致与订单不同步。
- 促销价显示异常:
- 核对promote_start_at与promote_end_at是否在有效期内。
- 检查level_price格式与会员等级映射是否正确。
- 搜索性能问题:
- 确认slug索引是否存在,必要时引入全文索引或搜索引擎。
- 检查列表页是否正确使用prefetchers预热资源。
结论
DouPHP的SKU与库存管理以product表为核心,结合订单状态机在付款后统一扣减库存与销售计数,并通过结账服务设置库存锁定标志,形成完整的下单-支付-扣减闭环。建议在现有基础上完善SKU编码规则、多规格组合、库存预警、批次管理与多仓调拨,同时在高并发场景下引入行级锁、分布式锁与库存快照,确保库存一致性与可追溯性。
附录:表结构与字段说明
- product表关键字段:
- id:主键,自增。
- title:商品标题。
- slug:URL友好标识,带索引。
- price:基础售价。
- promote_price:促销价。
- level_price:会员等级价格(字符串,建议JSON)。
- stock:可售库存。
- sales:累计销量。
- model:型号串(建议唯一)。
- status:上架状态。
- operator_type/operator_id:创建者类型与ID。
- created_at:创建时间。
- order_item表关键字段:
- id:主键。
- order_id:订单ID。
- module:模块标识(如product)。
- item_id:商品ID。
- item_number:购买数量。
- stock_lock:库存锁定标志(支付后清零)。
- order_status:订单状态快照。