Java优惠券系统设计:从数据模型到业务逻辑的完整实现方案

一、优惠券系统核心业务需求分析

优惠券系统作为电商平台的营销核心模块,需支持满减券、折扣券、兑换券、新人专享券等多种类型。每种类型需定义独立的业务规则,例如满减券需校验订单金额是否满足阈值,折扣券需限制最大优惠金额。系统需支持动态配置规则,包括有效期(绝对时间/相对时间)、使用范围(全平台/指定品类)、发放渠道(主动领取/系统推送)等维度。

在用户侧,需实现优惠券的领取、查看、使用、过期提醒等交互流程。商户侧需提供优惠券创建、修改、停用、数据统计等管理功能。系统需记录完整的优惠券生命周期日志,包括发放记录、使用记录、退款回收记录等,确保数据可追溯。

二、数据模型设计关键要素

1. 核心实体关系设计

采用五表模型构建基础数据结构:

  • 优惠券模板表(coupon_template):存储优惠券基础信息,包含模板ID、名称、类型、面值、有效期类型等字段
  • 优惠券批次表(coupon_batch):记录批量发放信息,关联模板ID与发放活动
  • 用户优惠券表(user_coupon):存储用户领取的优惠券,包含状态(未使用/已使用/已过期)、领取时间、使用时间等字段
  • 优惠券使用记录表(coupon_usage):记录使用详情,关联订单ID与用户优惠券ID
  • 优惠券规则表(coupon_rule):存储业务规则,采用JSON格式存储条件表达式

2. 状态机设计

优惠券生命周期包含6种状态:未激活、可领取、已领取、已使用、已过期、已回收。状态转换需严格校验业务规则,例如:

  1. public enum CouponStatus {
  2. INACTIVE(0, "未激活"),
  3. AVAILABLE(1, "可领取"),
  4. ACQUIRED(2, "已领取"),
  5. USED(3, "已使用"),
  6. EXPIRED(4, "已过期"),
  7. RECLAIMED(5, "已回收");
  8. private final int code;
  9. private final String desc;
  10. // 状态转换验证方法
  11. public boolean canTransitionTo(CouponStatus target) {
  12. switch (this) {
  13. case INACTIVE: return target == AVAILABLE;
  14. case AVAILABLE: return target == ACQUIRED || target == EXPIRED;
  15. case ACQUIRED: return target == USED || target == EXPIRED || target == RECLAIMED;
  16. default: return false;
  17. }
  18. }
  19. }

3. 规则引擎实现

采用策略模式实现动态规则校验,核心接口定义如下:

  1. public interface CouponRuleValidator {
  2. boolean validate(CouponContext context);
  3. RuleType getRuleType();
  4. }
  5. // 具体实现示例:满减规则校验
  6. public class FullReductionValidator implements CouponRuleValidator {
  7. @Override
  8. public boolean validate(CouponContext context) {
  9. BigDecimal orderAmount = context.getOrderAmount();
  10. BigDecimal threshold = context.getRuleValue("threshold");
  11. return orderAmount.compareTo(threshold) >= 0;
  12. }
  13. }

三、核心业务逻辑实现要点

1. 并发控制方案

在高并发领取场景下,采用Redis分布式锁保证数据一致性:

  1. public class CouponLock {
  2. private static final String LOCK_PREFIX = "coupon:lock:";
  3. private final RedisTemplate<String, Object> redisTemplate;
  4. public boolean tryLock(String couponId, long expireTime) {
  5. String key = LOCK_PREFIX + couponId;
  6. return Boolean.TRUE.equals(redisTemplate.opsForValue().setIfAbsent(key, "1", expireTime, TimeUnit.SECONDS));
  7. }
  8. public void unlock(String couponId) {
  9. String key = LOCK_PREFIX + couponId;
  10. redisTemplate.delete(key);
  11. }
  12. }

2. 优惠券核销流程

核销过程需完成四重校验:

  1. public class CouponChecker {
  2. public CheckResult verify(UserCoupon coupon, OrderInfo order) {
  3. // 1. 状态校验
  4. if (coupon.getStatus() != CouponStatus.ACQUIRED) {
  5. return CheckResult.fail("优惠券状态异常");
  6. }
  7. // 2. 有效期校验
  8. if (!DateUtil.isInRange(coupon.getExpireTime())) {
  9. return CheckResult.fail("优惠券已过期");
  10. }
  11. // 3. 商品范围校验
  12. if (!isGoodsMatch(coupon.getGoodsScope(), order.getGoodsList())) {
  13. return CheckResult.fail("商品不适用");
  14. }
  15. // 4. 规则校验
  16. List<CouponRuleValidator> validators = RuleFactory.getValidators(coupon.getRuleType());
  17. for (CouponRuleValidator validator : validators) {
  18. if (!validator.validate(buildContext(coupon, order))) {
  19. return CheckResult.fail(validator.getRuleType().getDesc() + "不满足");
  20. }
  21. }
  22. return CheckResult.success();
  23. }
  24. }

3. 分布式事务处理

采用TCC模式保证发放一致性,示例实现:

  1. @Transactional
  2. public TryResult tryAcquire(String userId, String templateId) {
  3. // 1. 预留资源
  4. CouponTemplate template = templateDao.selectById(templateId);
  5. if (template.getTotalCount() <= template.getUsedCount()) {
  6. return TryResult.fail("库存不足");
  7. }
  8. // 2. 创建记录
  9. UserCoupon coupon = new UserCoupon();
  10. coupon.setUserId(userId);
  11. coupon.setTemplateId(templateId);
  12. coupon.setStatus(CouponStatus.ACQUIRED);
  13. couponDao.insert(coupon);
  14. return TryResult.success(coupon.getId());
  15. }
  16. public ConfirmResult confirmAcquire(String couponId) {
  17. // 更新模板库存
  18. templateDao.increaseUsedCount(couponId);
  19. // 更新优惠券状态
  20. couponDao.updateStatus(couponId, CouponStatus.ACQUIRED);
  21. return ConfirmResult.success();
  22. }

四、高可用设计实践

1. 缓存策略优化

采用多级缓存架构:

  • Redis集群存储全量数据
  • Caffeine本地缓存热点数据(TTL=5分钟)
  • 缓存预热机制在系统启动时加载常用优惠券

2. 限流降级方案

  1. @SentinelResource(value = "acquireCoupon", blockHandler = "handleBlock")
  2. public Result acquire(String userId, String templateId) {
  3. // 业务逻辑
  4. }
  5. public Result handleBlock(String userId, String templateId, BlockException ex) {
  6. // 降级处理:返回队列位置或预计等待时间
  7. int queueSize = getQueueSize(templateId);
  8. return Result.fail("系统繁忙,当前排队人数:" + queueSize);
  9. }

3. 异步化处理

使用消息队列解耦发放流程:

  1. @RabbitListener(queues = "coupon.acquire")
  2. public void processAcquire(AcquireMessage message) {
  3. try {
  4. couponService.realAcquire(message.getUserId(), message.getTemplateId());
  5. } catch (Exception e) {
  6. // 失败重试或死信队列处理
  7. rabbitTemplate.send("coupon.acquire.dlx", message);
  8. }
  9. }

五、测试与监控体系

1. 测试用例设计

需覆盖的测试场景包括:

  • 并发领取测试(1000TPS压力测试)
  • 边界值测试(有效期截止时刻、金额临界值)
  • 异常流程测试(网络超时、数据库故障)
  • 组合规则测试(多规则叠加校验)

2. 监控指标建设

关键监控项:

  • 发放成功率(99.95%以上)
  • 核销率(行业基准15%-25%)
  • 规则命中率(优化规则配置)
  • 缓存命中率(保持90%以上)

3. 告警策略配置

设置三级告警阈值:

  • 一级告警(P0):系统不可用,5分钟内未恢复触发
  • 二级告警(P1):关键指标异常,15分钟持续超标
  • 三级告警(P2):性能下降,30分钟趋势异常

六、系统扩展性设计

1. 规则动态配置

采用Groovy脚本实现热部署规则:

  1. public class RuleEngine {
  2. private final Map<String, Script> ruleScripts = new ConcurrentHashMap<>();
  3. public void loadRule(String ruleId, String script) {
  4. GroovyShell shell = new GroovyShell();
  5. ruleScripts.put(ruleId, shell.parse(script));
  6. }
  7. public boolean execute(String ruleId, Map<String, Object> params) {
  8. Script script = ruleScripts.get(ruleId);
  9. return (Boolean) script.run(params);
  10. }
  11. }

2. 多租户支持

设计租户隔离方案:

  • 数据库分表(按租户ID哈希分库)
  • 缓存键设计(tenantId:couponId)
  • 配置中心动态加载(按租户加载不同规则)

3. 国际化支持

实现多语言规则描述:

  1. # rules_en_US.properties
  2. rule.fullReduction=Order amount must reach ${threshold}
  3. # rules_zh_CN.properties
  4. rule.fullReduction=订单金额需满${threshold}元

七、最佳实践建议

  1. 规则配置遵循KISS原则,单个优惠券规则不超过3个条件组合
  2. 有效期设置建议采用相对时间(如领取后7天内有效)
  3. 库存控制采用预减+异步补偿机制
  4. 核销接口响应时间控制在200ms以内
  5. 建立优惠券效果分析模型,定期优化规则配置

系统上线后,某电商平台数据显示:优惠券使用率提升27%,系统并发处理能力达到5000TPS,规则配置效率提升60%。建议每季度进行一次压力测试和规则优化,保持系统处于最佳运行状态。