文档目录
库存核心表

简介

本文件面向电商平台开发者,系统化梳理 DouPHP 电商系统的库存核心数据模型与计算逻辑。重点说明:

  • 库存主表设计(以 product 表的 stock 字段为核心)
  • 订单维度库存锁定字段 stock_lock 的作用
  • 实时库存、在途库存、安全库存、预警库存的计算方法
  • 并发场景下的库存锁定与释放机制
  • 数据一致性保证、事务处理与性能优化建议

项目结构

围绕库存的核心代码主要分布在以下位置:

  • 数据库定义:系统表结构 SQL 中定义了 product 与 order_item 等关键表
  • 模型层:product 模块的后台/前台 Model 声明了 stock/sales 等字段的类型与行为
  • 订单流程:购物车、结账、订单状态迁移中涉及库存检查、锁定与扣减
graph TB
A["产品表(dou_product)"] --> B["订单商品明细(dou_order_item)"]
C["购物车服务"] --> D["结账服务"]
D --> E["订单状态迁移"]
E --> A
E --> B

核心组件

  • 产品表(dou_product)
    • 关键字段:id、stock、sales、price、promote_price、status 等
    • stock 表示当前可用库存;sales 表示累计销量
  • 订单商品明细(dou_order_item)
    • 关键字段:item_id、item_number、stock_lock、order_status 等
    • stock_lock 用于标记该订单项是否占用库存
  • 产品模型(Product)
    • 声明 stock/sales 为整型,便于业务层进行数量运算
  • 订单流程服务
    • 购物车:下单前校验库存
    • 结账:根据配置决定是否锁定库存
    • 订单状态迁移:支付成功后扣减库存并累加销量

架构总览

库存相关的关键交互如下:

  • 用户添加购物车时,调用库存检查接口,防止超卖
  • 创建订单时,依据站点配置决定是否锁定库存
  • 订单支付成功后,执行库存扣减与销量累加
  • 订单取消或退款时,需释放已锁定的库存
sequenceDiagram
participant U as "用户"
participant C as "购物车服务"
participant O as "结账服务"
participant S as "订单状态迁移"
participant P as "产品表(stock)"
participant I as "订单商品明细(stock_lock)"
U->>C : 加入购物车(含数量)
C->>P : 检查库存(可购买性)
C-->>U : 返回结果
U->>O : 提交订单
O->>I : 写入订单项(设置stock_lock=1或0)
O-->>U : 返回订单号
U->>S : 支付成功回调
S->>P : 扣减库存(stock -= item_number)
S->>P : 累加销量(sales += item_number)
S-->>U : 返回支付完成

详细组件分析

库存主表设计(dou_product)

  • 表名:dou_product
  • 关键字段
    • id:商品唯一标识
    • stock:库存数量(整型),表示当前可用库存
    • sales:累计销量(整型),用于统计与展示
    • price/promote_price:价格与促销价,影响可售性与展示
    • status:上架状态,仅上架商品参与销售
  • 设计要点
    • stock 作为“可用库存”的权威来源,所有扣减均基于此字段
    • sales 与 stock 保持联动:每笔有效交易完成后,stock 减少、sales 增加
    • 通过 casts 将 stock/sales 强制为整型,避免字符串运算导致精度问题
erDiagram
dou_product {
int id PK
smallint stock
mediumint sales
decimal price
decimal promote_price
tinyint status
}

订单维度库存锁定(dou_order_item.stock_lock)

  • 表名:dou_order_item
  • 关键字段
    • item_id:关联商品ID
    • item_number:购买数量
    • stock_lock:是否锁定库存(tinyint,默认1表示锁定)
    • order_status:订单状态,用于判断是否应释放锁定
  • 作用
    • 在订单创建阶段,若启用库存锁定,则对相应商品进行“预占”
    • 当订单取消/过期/退款时,需释放对应数量的锁定库存
    • 与 product.stock 配合,实现“可用库存 = 实际库存 - 锁定库存”的业务视图
flowchart TD
Start(["创建订单"]) --> CheckCfg{"是否启用库存锁定?"}
CheckCfg --> |是| Lock["写入stock_lock=1<br/>预占库存"]
CheckCfg --> |否| Skip["不锁定库存"]
Lock --> End(["等待支付"])
Skip --> End

库存计算逻辑

  • 实时库存
    • 定义:当前可用于销售的库存数量
    • 计算:real_stock = product.stock - sum(order_item.item_number where stock_lock=1 and not paid/cancelled/refunded)
    • 说明:未支付的锁定订单会占用可用库存;支付成功后转为实际扣减
  • 在途库存
    • 定义:已锁定但尚未完成支付的库存
    • 计算:in_transit = sum(order_item.item_number where stock_lock=1 and order_status in pending/paid_not_shipped)
    • 用途:用于库存看板与预警
  • 安全库存
    • 定义:为避免缺货而保留的最小库存阈值
    • 计算:由运营策略决定,通常作为常量或配置项
    • 用途:当 real_stock &lt; safety_stock 时触发补货提醒
  • 预警库存
    • 定义:低于安全库存时的告警阈值
    • 计算:alert_stock = safety_stock * 系数(如1.2)
    • 用途:当 real_stock &lt; alert_stock 时发出预警
flowchart TD
A["读取product.stock"] --> B["汇总锁定库存(未支付/未发货)"]
B --> C["计算real_stock = stock - 锁定库存"]
C --> D{"real_stock < safety_stock ?"}
D --> |是| E["触发补货提醒"]
D --> |否| F["正常销售"]
C --> G{"real_stock < alert_stock ?"}
G --> |是| H["发出预警通知"]
G --> |否| I["继续监控"]

库存锁定与释放机制(并发安全)

  • 锁定时机
    • 购物车阶段:检查库存是否足够,防止超卖
    • 结账阶段:根据站点配置决定是否锁定库存(stock_lock=1)
  • 释放时机
    • 订单取消/过期:释放锁定库存(恢复 real_stock)
    • 订单支付成功:从 product.stock 中扣减对应数量,并累加 sales
  • 并发控制建议
    • 使用数据库行级锁或乐观锁(version 字段)确保并发更新的一致性
    • 在扣减库存时使用原子更新语句,避免竞态条件
    • 对高频热点商品采用队列化异步扣减,降低数据库压力
sequenceDiagram
participant T as "线程A"
participant DB as "数据库"
participant P as "product.stock"
participant I as "order_item.stock_lock"
T->>DB : 开始事务
DB->>P : SELECT stock FOR UPDATE
DB->>I : 查询锁定库存
DB-->>T : 返回stock与锁定量
T->>DB : 计算real_stock并校验
T->>DB : 更新stock_lock或扣减stock
DB-->>T : 提交事务

数据一致性保证与事务处理

  • 一致性原则
    • 任何库存变更必须与订单状态变更在同一事务内完成
    • 扣减库存与累加销量必须成对出现,避免不一致
  • 事务边界
    • 创建订单:写入 order_item 与 stock_lock
    • 支付成功:扣减 product.stock 与增加 sales
    • 取消/退款:释放 stock_lock 或回滚库存
  • 幂等性
    • 支付回调需具备幂等处理,避免重复扣减库存
  • 审计与日志
    • 记录库存变更日志,便于追踪与对账
flowchart TD
Start(["订单支付成功"]) --> Txn["开启事务"]
Txn --> Deduct["扣减product.stock"]
Deduct --> AddSales["累加product.sales"]
AddSales --> Commit["提交事务"]
Commit --> End(["完成"])

性能优化方案

  • 索引优化
    • 为 product.id、order_item.item_id、order_item.order_id 建立索引
    • 为 order_item 的 stock_lock、order_status 建立复合索引,加速锁定库存汇总
  • 读写分离
    • 读多写少场景下,使用只读副本查询库存快照
  • 缓存策略
    • 对热点商品的 stock/sales 使用内存缓存(如 Redis),缩短读取路径
    • 使用延迟双检模式,避免频繁落库
  • 批处理与异步
    • 批量扣减库存时采用分批提交,降低锁竞争
    • 非关键路径(如统计报表)异步处理

依赖关系分析

  • 产品表与订单商品明细的依赖
    • order_item.item_id 引用 product.id
    • stock_lock 与 product.stock 共同决定可用库存
  • 服务层依赖
    • 购物车服务依赖库存检查能力
    • 结账服务依据配置决定是否锁定库存
    • 订单状态迁移负责最终扣减与销量累加
graph LR
P["product.stock"] --> OI["order_item.stock_lock"]
CS["购物车服务"] --> CK["结账服务"]
CK --> OT["订单状态迁移"]
OT --> P
OT --> OI

性能考虑

  • 高并发下单
    • 使用数据库行级锁或分布式锁,避免超卖
    • 对热点商品采用分片或队列化扣减
  • 查询优化
    • 聚合锁定库存时尽量使用索引覆盖扫描
    • 避免全表扫描与复杂子查询
  • 缓存与降级
    • 对只读场景使用缓存,提升响应速度
    • 在极端情况下允许短暂的数据不一致,事后补偿

故障排查指南

  • 常见问题
    • 库存为负:检查是否存在并发扣减未加锁或重复回调
    • 锁定库存未释放:检查订单取消/过期流程是否正确释放 stock_lock
    • 销量与库存不一致:核对支付成功后的扣减与累加是否在同一事务
  • 定位步骤
    • 查看订单状态与 stock_lock 字段,确认锁定状态
    • 核对 product.stock 与 order_item 的数量变化
    • 检查是否有重复支付回调导致的重复扣减
  • 修复建议
    • 引入幂等键与去重表,防止重复处理
    • 增加库存变更审计日志,便于追溯
    • 对异常数据进行对账与补偿脚本

结论

DouPHP 的库存核心以 product.stock 为权威数据源,结合 order_item.stock_lock 实现订单维度的库存锁定与释放。通过购物车检查、结账锁定、支付扣减的三段式流程,保障库存一致性与防超卖。建议在并发场景下采用行级锁/乐观锁与队列化异步处理,并结合索引、缓存与审计日志,构建高性能、可观测的库存体系。

附录

  • 字段参考
    • product.stock:可用库存
    • product.sales:累计销量
    • order_item.stock_lock:是否锁定库存
    • order_item.item_number:购买数量
  • 建议扩展
    • 增加 inventory_log 表记录每次库存变更
    • 引入 version 字段支持乐观锁
    • 提供库存盘点与对账工具
添加日期:2026-10-05