简介
本文件面向电商平台开发者,系统化梳理 DouPHP 电商系统的优惠券数据模型,重点围绕以下目标:
- 明确优惠券主表 dou_coupon、使用记录表 dou_coupon_log、订单关联表 dou_order_coupon 的字段设计与业务含义
- 解释优惠券类型、发放规则、使用条件、有效期管理、库存控制等关键业务在表结构中的体现
- 描述优惠券与用户、订单、商品的关联关系及状态流转机制
- 给出并发控制、防刷机制与性能优化的可落地方案
- 提供基于现有代码与SQL的完整参考,便于二次开发与扩展
项目结构
与优惠券相关的核心数据定义集中在以下位置:
- 系统级表结构文档:_'\doc\开发手册\系统表结构.sql(包含历史/兼容版本的表结构)
- 模块级备份脚本:_'\module\coupon\storage\backup\coupon.sql(当前模块使用的表结构)
- 订单模块关联表:_'\module\order\storage\backup\order.sql(订单与优惠券的关联表)
- 管理端模型:admin\model\coupon\Coupon.php、admin\model\coupon\CouponLog.php(ORM映射与查询封装)
graph TB
A["优惠券主表<br/>dou_coupon"] --> B["领取/使用日志表<br/>dou_coupon_log"]
A --> C["订单-优惠券关联表<br/>dou_order_coupon"]
B --> C
D["订单主表<br/>dou_order"] -.-> C
E["用户表<br/>dou_user"] -.-> B
核心组件
本节聚焦三张核心表的设计要点与字段语义。
-
优惠券主表 dou_coupon
- 标识与名称:id、name、coupon_sn(唯一券码)
- 优惠策略:type(类型)、face_value(面值)、max_discount(封顶折扣,部分版本存在)、condition(使用门槛金额)
- 范围与限制:scope_type、scope_value(适用范围,如全店/指定类目/指定商品)、limit_per_user(每人限领数量)、is_stackable(是否可叠加)、is_first_order_only(是否仅限首单)
- 库存与生命周期:total_quantity(总量)、issued_quantity(已发放量)、start_at/end_at(有效期)
- 展示与排序:brief、image、sort、status(启用/禁用)、created_at
-
优惠券使用记录表 dou_coupon_log
- 主体信息:user_id、coupon_id
- 时间戳:claimed_at(领取时间)、used_at(使用时间)、created_at
- 使用上下文:order_sn(使用时的订单号)、ip(操作IP)
- 状态:status(如未使用/已使用/已过期等)
-
订单-优惠券关联表 dou_order_coupon
- 关联键:order_id、coupon_id、coupon_log_id
- 优惠明细:amount(本次抵扣金额)、type(优惠类型)
- 时间:created_at
架构总览
从数据流角度,优惠券的核心流程包括“创建/配置 → 发放 → 使用 → 结算”。
sequenceDiagram
participant Admin as "管理员"
participant Coupon as "优惠券主表<br/>dou_coupon"
participant Log as "使用记录表<br/>dou_coupon_log"
participant Order as "订单-优惠券关联表<br/>dou_order_coupon"
participant User as "用户"
participant OrderMain as "订单主表<br/>dou_order"
Admin->>Coupon : 创建/编辑优惠券
User->>Log : 领取优惠券(写入领取记录)
User->>Order : 下单并选择优惠券
Order->>Log : 校验并标记使用(更新状态/时间)
Order->>Order : 计算实付金额(应用优惠)
Order->>Order : 保存订单-优惠券关联(记录抵扣金额)
详细组件分析
优惠券主表 dou_coupon
- 设计要点
- 唯一性:coupon_sn 作为对外唯一券码,建议加唯一索引
- 范围控制:scope_type/scope_value 支持灵活限定(全店/类目/商品),通过文本或JSON存储
- 库存控制:total_quantity 与 issued_quantity 配合,发放时原子递增,避免超发
- 有效期:start_at/end_at 精确到分钟,便于活动期控制
- 叠加与限制:is_stackable、is_first_order_only、limit_per_user 控制使用策略
- 典型索引建议
- 唯一索引:coupon_sn
- 查询索引:status、start_at、end_at、scope_type
- 与业务的关系
- 与用户:通过 dou_coupon_log.user_id 建立“谁领了哪张券”
- 与订单:通过 dou_order_coupon.order_id/coupon_id 建立“哪个订单用了哪张券”
- 与商品:通过 scope_value 间接限定适用商品范围
优惠券使用记录表 dou_coupon_log
- 设计要点
- 领取与使用分离:claimed_at 与 used_at 分别记录,便于统计与审计
- 使用上下文:order_sn 用于回溯具体订单;ip 用于风控
- 状态机:status 表示当前状态(未使用/已使用/已过期/已取消等)
- 典型索引建议
- 复合索引:(user_id, coupon_id) 用于查询某用户某券的使用情况
- 复合索引:(coupon_id, status) 用于统计可用券
- 时间索引:(used_at) 用于按使用时间统计
- 与业务的关系
- 与用户:user_id 指向用户
- 与订单:order_sn 指向订单号(需结合订单表)
- 与主券:coupon_id 指向 dou_coupon.id
订单-优惠券关联表 dou_order_coupon
- 设计要点
- 多对多桥接:order_id + coupon_id + coupon_log_id 共同定位一次使用
- 优惠明细:amount 记录实际抵扣金额,type 区分优惠类型(满减/折扣等)
- 典型索引建议
- 索引:order_id(订单维度查询)
- 复合索引:(coupon_id, order_id)(券维度查询)
- 与业务的关系
- 与订单:order_id 指向订单主表
- 与券:coupon_id 指向优惠券主表
- 与日志:coupon_log_id 指向使用记录,形成闭环
优惠券类型与使用条件
- 类型 type
- 常见值:满减、折扣、无门槛等(具体枚举由业务层定义)
- 使用条件 condition
- 最低消费门槛,满足后方可使用
- 其他限制
- is_first_order_only:仅首单可用
- limit_per_user:每人限领数量
- is_stackable:是否可与其他优惠叠加
- scope_type/scope_value:适用范围(全店/类目/商品)
有效期管理与库存控制
- 有效期
- start_at/end_at 控制活动窗口,使用前校验是否在有效期内
- 库存控制
- total_quantity 为总量,issued_quantity 为已发放量
- 发放时需原子递增 issued_quantity,防止超发
- 使用时无需再扣减库存(以使用次数/状态为准)
状态流转机制
- 主要状态
- 未使用:领取后尚未使用
- 已使用:成功用于订单支付
- 已过期:超过 end_at 仍未使用
- 已取消:主动取消或回滚
- 流转约束
- 未使用 → 已使用:需满足条件(有效期、门槛、范围、叠加规则)
- 未使用 → 已过期:时间到达 end_at
- 已使用 → 已取消:订单退款/撤销时回滚
stateDiagram-v2
[*] --> 未使用 : "领取"
未使用 --> 已使用 : "满足条件并使用"
未使用 --> 已过期 : "超过有效期"
已使用 --> 已取消 : "订单退款/撤销"
已过期 --> [*]
已取消 --> [*]
[此图为概念图,不直接映射具体代码文件]
依赖关系分析
- 表间关系
- dou_coupon 与 dou_coupon_log:一对多(一张券可被多次领取/使用)
- dou_coupon_log 与 dou_order_coupon:一对多(一条使用记录对应一次订单使用)
- dou_order_coupon 与 dou_order:多对一(一个订单可使用多张券)
- ORM 映射
- admin/model/coupon/Coupon.php 映射 dou_coupon
- admin/model/coupon/CouponLog.php 映射 dou_coupon_log
erDiagram
DOU_COUPON {
int id PK
varchar name
varchar coupon_sn UK
varchar type
decimal face_value
decimal max_discount
smallint limit_per_user
int total_quantity
int issued_quantity
tinyint is_stackable
tinyint is_first_order_only
decimal condition
varchar scope_type
text scope_value
datetime start_at
datetime end_at
varchar brief
varchar image
tinyint sort
tinyint status
datetime created_at
}
DOU_COUPON_LOG {
int id PK
mediumint user_id
mediumint coupon_id FK
datetime claimed_at
datetime used_at
varchar order_sn
varchar ip
tinyint status
datetime created_at
}
DOU_ORDER_COUPON {
int id PK
int order_id FK
mediumint coupon_id FK
int coupon_log_id FK
decimal amount
varchar type
datetime created_at
}
DOU_COUPON ||--o{ DOU_COUPON_LOG : "被领取/使用"
DOU_COUPON_LOG ||--o{ DOU_ORDER_COUPON : "用于订单"
DOU_ORDER ||--o{ DOU_ORDER_COUPON : "包含"
性能与并发优化
- 数据库层面
- 索引优化
- dou_coupon:唯一索引(coupon_sn),复合索引(status, start_at, end_at)
- dou_coupon_log:复合索引(user_id, coupon_id)、(coupon_id, status)、(used_at)
- dou_order_coupon:索引(order_id)、复合索引(coupon_id, order_id)
- 事务与锁
- 发放与使用使用事务包裹,必要时使用行级锁或乐观锁(版本号)
- 库存控制使用原子更新(如 UPDATE ... SET issued_quantity = issued_quantity + 1 WHERE id = ? AND issued_quantity < total_quantity)
- 索引优化
- 应用层
- 防刷机制
- 接口限频:同一用户/IP短时间领取/使用次数限制
- 幂等设计:基于 coupon_sn + user_id + order_sn 的唯一键或分布式锁
- 风控校验:设备指纹、验证码、黑名单
- 缓存与预取
- 热点券信息(如活动券)缓存至内存,减少DB压力
- 使用资格校验结果短期缓存,降低重复计算
- 异步化
- 非关键路径(如发送通知、写日志)采用消息队列异步处理
- 读写分离
- 读多写少场景下,将统计类查询路由到从库
- 防刷机制
故障排查指南
- 常见问题定位
- 无法领取:检查库存(total_quantity > issued_quantity)、有效期(当前时间在 start_at/end_at 之间)、每人限领(limit_per_user)
- 无法使用:检查使用条件(condition)、适用范围(scope_type/scope_value)、叠加规则(is_stackable)、首单限制(is_first_order_only)
- 重复使用:检查 dou_coupon_log 中是否存在相同 user_id + coupon_id + order_sn 的记录
- 排查步骤
- 查看 dou_coupon_log 的状态与时间戳,确认领取/使用是否成功
- 核对 dou_order_coupon 的 amount 与 type,确认优惠是否生效
- 检查 dou_coupon 的 status、start_at、end_at 与 scope 配置
- 日志与审计
- 利用 ip、order_sn、user_id 进行溯源
- 结合订单状态变更日志,定位异常订单
结论
- 数据模型清晰:dou_coupon 定义优惠策略与限制,dou_coupon_log 记录领取与使用轨迹,dou_order_coupon 沉淀订单维度的优惠明细
- 业务可扩展:通过 scope_type/scope_value、type、is_stackable 等字段支撑多样化营销场景
- 并发与安全:结合索引、事务、锁与接口限频,保障高并发下的正确性与安全性
- 建议持续完善:根据业务演进补充更细粒度的范围控制、风控策略与监控指标
附录
- 字段字典(节选)
- dou_coupon
- id:自增主键
- name:优惠券名称
- coupon_sn:唯一券码
- type:优惠券类型
- face_value:面值
- max_discount:封顶折扣(部分版本)
- limit_per_user:每人限领数量
- total_quantity:总量
- issued_quantity:已发放量
- is_stackable:是否可叠加
- is_first_order_only:是否仅限首单
- condition:使用门槛金额
- scope_type:适用范围类型
- scope_value:适用范围值(类目/商品ID列表等)
- start_at:开始时间
- end_at:结束时间
- brief:简介
- image:图片
- sort:排序
- status:状态(启用/禁用)
- created_at:创建时间
- dou_coupon_log
- id:自增主键
- user_id:会员ID
- coupon_id:优惠券ID
- claimed_at:领取时间
- used_at:使用时间
- order_sn:订单号
- ip:操作IP
- status:状态
- created_at:创建时间
- dou_order_coupon
- id:自增主键
- order_id:订单ID
- coupon_id:优惠券ID
- coupon_log_id:使用记录ID
- amount:抵扣金额
- type:优惠类型
- created_at:创建时间
- dou_coupon