Java面试要点:优惠券领取、核销、过期、叠加规则与防薅羊毛
前言
优惠券是典型的“看起来简单,生产很复杂”的业务。面试常问:
- 优惠券怎么防止超发。
- 下单时怎么锁定优惠券。
- 支付失败后优惠券怎么返还。
- 多张券叠加规则怎么设计。
- 怎么防止批量薅羊毛。
优惠券生命周期
stateDiagram-v2
[*] --> 待领取
待领取 --> 已领取: 用户领取
已领取 --> 已锁定: 下单使用
已锁定 --> 已核销: 支付成功
已锁定 --> 已领取: 支付失败/取消
已领取 --> 已过期: 超过有效期
优惠券状态不能随意跳转,尤其是已核销不能再次使用。
领取怎么设计
领取要解决库存和资格问题。
常见校验:
- 活动是否开始。
- 用户是否满足资格。
- 用户是否超过领取次数。
- 总库存是否足够。
- 是否命中风控规则。
并发领取常见方案:
| 方案 | 优点 | 缺点 |
|---|---|---|
| 数据库扣库存 | 简单 | 高并发压力大 |
| Redis 预扣库存 | 性能好 | 需要补偿 |
| MQ 排队领取 | 稳定 | 用户结果延迟 |
核销怎么设计
优惠券核销通常发生在支付成功后,而不是提交订单时直接最终核销。
下单时:
- 校验券可用。
- 锁定优惠券。
- 记录订单和券关系。
支付成功:
- 把锁定状态改为已核销。
支付失败或超时:
- 释放锁定。
这样可以避免用户下单不支付却长期占用优惠券。
叠加规则
营销规则常见维度:
- 满减券。
- 折扣券。
- 品类券。
- 商品券。
- 运费券。
- 平台券和店铺券。
叠加规则可以分为:
- 不可叠加。
- 同类型不可叠加,不同类型可叠加。
- 按优先级叠加。
- 用户选择最优组合。
复杂营销建议抽象成规则引擎:
flowchart TD
A[订单金额和商品明细] --> B[筛选可用券]
B --> C[计算每张券优惠]
C --> D[应用叠加规则]
D --> E[返回最优优惠结果]
防薅羊毛
常见风险:
- 批量注册。
- 多账号领取。
- 接码平台。
- 异常设备。
- 异常 IP。
- 领券后批量下单退款。
防护措施:
- 领取频率限制。
- 用户实名或手机号校验。
- 设备指纹。
- 黑名单。
- 风控评分。
- 高风险订单人工审核。
高频面试题
优惠券为什么要有锁定状态?
因为用户下单后不一定支付。锁定状态可以防止同一张券被多个订单同时使用,又能在订单取消后释放。
怎么防止优惠券超发?
用 Redis 原子扣减、数据库唯一约束、领取记录去重和异步补偿共同保证。
优惠券过期怎么处理?
可以通过定时任务扫描,也可以查询时判断有效期。大规模场景通常定时归档加查询实时判断结合。
叠加规则怎么设计?
把规则从代码 if else 中抽象出来,按券类型、适用范围、优先级和互斥关系计算。
总结
优惠券营销的关键是状态机、库存控制、核销幂等、规则计算和风控。企业落地时,优惠券不是简单折扣字段,而是一个带生命周期、库存、资格、风控和财务影响的业务系统。
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 Junly博客!
评论


