券模板、用户券、锁券核销怎么配合?一次讲透

张开发
2026/6/23 19:07:05 15 分钟阅读
券模板、用户券、锁券核销怎么配合?一次讲透
电商优惠券系统怎么设计一次讲清领券、用券、叠加规则、核销与风控思路大家好我是一名有 4 年工作经验的 Java 后端开发。优惠券系统在电商里看起来像营销模块但真正做起来会发现它几乎把状态、并发、规则、风控、资金口径全都串到了一起。这篇文章我想系统聊一聊优惠券系统到底应该怎么设计。个人主页文章目录电商优惠券系统怎么设计一次讲清领券、用券、叠加规则、核销与风控思路一、前言二、核心模型怎么拆2.1 券模板2.2 用户券2.3 券使用记录三、推荐状态设计四、最关键的几个问题4.1 怎么防止重复领券4.2 怎么防止超发4.3 下单时怎么选券4.4 为什么要有锁券状态五、数据库示例5.1 券模板表5.2 用户券表5.3 用户券流水表六、最容易踩的坑6.1 把券模板和用户券混在一起6.2 没有锁券状态6.3 规则计算和发券逻辑耦合太深6.4 只考虑领券不考虑回滚和核销七、面试中怎么回答八、总结九、结尾一、前言优惠券系统常见的问题包括用户重复领券券被超发下单时算券很慢多张券叠加规则复杂支付失败后券状态回滚不一致活动结束后数据对不上所以优惠券系统真正要解决的不只是“发几张券”而是规则配置、领券控制、用券核销、状态流转和风控约束的完整闭环。二、核心模型怎么拆我更建议至少拆成三层2.1 券模板描述规则满减 / 折扣 / 直减使用门槛生效时间叠加规则适用范围2.2 用户券描述实例归属用户当前状态领取时间使用时间2.3 券使用记录描述动作何时领取何时锁定何时核销何时回滚三、推荐状态设计用户券通常建议至少有这些状态INITAVAILABLELOCKEDUSEDEXPIREDINVALID其中下单提交时可以先LOCKED支付成功后变USED订单取消或支付失败再从LOCKED回滚成AVAILABLE四、最关键的几个问题4.1 怎么防止重复领券常见做法用户券表唯一索引领券接口幂等Redis 前置限流 / 防重4.2 怎么防止超发常见做法券模板库存字段条件更新扣库存活动高峰可加 Redis 预扣减4.3 下单时怎么选券核心思路通常是先筛掉不满足门槛和范围的券再根据叠加规则过滤再从剩余券里挑最优组合如果规则复杂最好有独立的优惠计算服务4.4 为什么要有锁券状态因为用户提交订单后不一定马上支付成功。这时候券已经参与了订单计算但又不能立即真正核销所以通常要有LOCKED支付成功后LOCKED - USED支付失败或取消后LOCKED - AVAILABLE五、数据库示例5.1 券模板表CREATETABLEcoupon_template(idBIGINTPRIMARYKEYAUTO_INCREMENT,nameVARCHAR(64)NOTNULL,typeVARCHAR(32)NOTNULL,total_countINTNOTNULL,remain_countINTNOTNULL,threshold_amountDECIMAL(10,2)DEFAULTNULL,discount_amountDECIMAL(10,2)DEFAULTNULL,start_timeDATETIMENOTNULL,end_timeDATETIMENOTNULL,statusVARCHAR(16)NOTNULL);5.2 用户券表CREATETABLEuser_coupon(idBIGINTPRIMARYKEYAUTO_INCREMENT,user_idBIGINTNOTNULL,template_idBIGINTNOTNULL,statusVARCHAR(16)NOTNULL,order_idBIGINTDEFAULTNULL,received_atDATETIMENOTNULLDEFAULTCURRENT_TIMESTAMP,used_atDATETIMEDEFAULTNULL);5.3 用户券流水表CREATETABLEuser_coupon_log(idBIGINTPRIMARYKEYAUTO_INCREMENT,user_coupon_idBIGINTNOTNULL,actionVARCHAR(32)NOTNULL,from_statusVARCHAR(16)DEFAULTNULL,to_statusVARCHAR(16)DEFAULTNULL,biz_idBIGINTDEFAULTNULL,created_atDATETIMENOTNULLDEFAULTCURRENT_TIMESTAMP);六、最容易踩的坑6.1 把券模板和用户券混在一起后面状态会特别乱。6.2 没有锁券状态支付失败和取消场景很容易失控。6.3 规则计算和发券逻辑耦合太深后面扩展很痛苦。6.4 只考虑领券不考虑回滚和核销这几乎一定会在上线后出问题。七、面试中怎么回答如果面试官问你电商优惠券系统一般怎么设计你可以这样回答第一优惠券系统我一般会拆成券模板、用户券和券流水三层。模板负责定义规则用户券负责实例状态流水负责追踪动作。第二用户券状态至少会设计成可用、锁定、已使用、已过期这几类。下单时先锁券支付成功后核销支付失败或取消时回滚。第三领券和用券这两个过程都需要考虑幂等和并发控制比如用户重复领券、模板库存超发、支付失败回滚等问题。第四如果优惠规则复杂我会单独抽优惠计算服务而不是把券计算直接写死在订单服务里。八、总结优惠券系统真正难的不是表设计而是如何把规则状态并发核销回滚这些环节串成闭环。如果只记一句结论我觉得可以记住这句优惠券系统最稳的做法通常不是只做发券而是“模板、用户券、流水三层拆分 锁券核销回滚闭环”。九、结尾如果你觉得这篇文章对你有帮助欢迎点赞、收藏、关注。后面我会继续整理一些更偏实战的 Java 后端和电商系统设计文章。

更多文章