当前位置: 首页 > news >正文

电商系统防重实战:三招解决订单重复创建难题

文章目录

  • 一、重复订单引发的血泪教训
  • 二、三大防重方案深度解析
    • 2.1 方案一:Token令牌验证方案
      • 2.1.1 实现原理
      • 2.1.2 关键实现步骤
      • 2.1.3 方案特点
    • 2.2 方案二:分布式锁方案
      • 2.2.1 锁键设计原则
      • 2.2.2 Redisson实现示例
      • 2.2.3 方案特点
    • 2.3 方案三:Token+分布式锁双保险方案
      • 2.3.1 双重校验流程
      • 2.3.2 代码实现示例
      • 2.3.3 方案特点
  • 三、方案对比与选型建议
  • 四、生产环境注意事项

一、重复订单引发的血泪教训

某电商大促期间,由于网络抖动导致用户重复点击下单按钮,产生大量重复订单,最终引发:

  • 库存超卖导致订单无法履约
  • 用户重复支付引发客诉
  • 财务对账出现百万级差额

这些惨痛教训告诉我们:防重设计是电商系统的生命线


二、三大防重方案深度解析

2.1 方案一:Token令牌验证方案

2.1.1 实现原理

客户端                服务端
  |--获取Token请求--->| 生成Token存入Redis
  |<--返回Token-----|
  |--提交订单(Token)->| 校验Token是否有效

2.1.2 关键实现步骤

  1. Token生成策略

    // 使用UUID+时间戳生成唯一标识
    String token = UUID.randomUUID().toString() + "_" + System.currentTimeMillis();
    
  2. Redis存储设计

    // 存储结构示例
    redisTemplate.opsForValue().set(
        "order:token:" + userId, 
        token, 
        5,  // 5秒过期时间
        TimeUnit.SECONDS);
    
  3. 原子性校验逻辑

    @PostMapping("/createOrder")
    public Result createOrder(@RequestParam String token) {
        String redisKey = "order:token:" + getUserId();
        // 使用Lua脚本保证原子性
        String luaScript = "if redis.call('get', KEYS[1]) == ARGV[1] " +
                           "then return redis.call('del', KEYS[1]) " +
                           "else return 0 end";
        
        Long result = redisTemplate.execute(
            new DefaultRedisScript<>(luaScript, Long.class),
            Collections.singletonList(redisKey),
            token);
        
        if(result == 1L){
            // 执行创建订单逻辑
            return doCreateOrder();
        } else {
            throw new BusinessException("请勿重复提交订单");
        }
    }
    

2.1.3 方案特点

  • 优点:实现简单、性能损耗小
  • 缺点:依赖客户端传递Token

2.2 方案二:分布式锁方案

2.2.1 锁键设计原则

lock_key = "order_lock:{userId}:{businessType}"  
// 示例:order_lock:12345:normal_order

2.2.2 Redisson实现示例

public Result createOrderWithLock(Long userId) {
    String lockKey = "order_lock:" + userId + ":normal";
    RLock lock = redissonClient.getLock(lockKey);
    
    try {
        // 尝试加锁,最多等待100ms,锁持有时间30秒
        if(lock.tryLock(100, 30000, TimeUnit.MILLISECONDS)) {
            return doCreateOrder();
        } else {
            throw new BusinessException("操作过于频繁,请稍后重试");
        }
    } finally {
        if(lock.isLocked() && lock.isHeldByCurrentThread()) {
            lock.unlock();
        }
    }
}

2.2.3 方案特点

  • 优点:实时性强、可靠性高
  • 缺点:增加系统复杂度

2.3 方案三:Token+分布式锁双保险方案

2.3.1 双重校验流程

1. 前端获取Token
2. 提交订单时携带Token
3. 服务端先验证Token有效性
4. Token验证通过后获取分布式锁
5. 执行业务逻辑

2.3.2 代码实现示例

public Result createOrderWithDoubleCheck(String token) {
    // 第一步:校验Token
    String redisKey = "order:token:" + getUserId();
    Long tokenValid = checkToken(redisKey, token);
    
    if(tokenValid != 1L) {
        throw new BusinessException("非法请求");
    }
    
    // 第二步:获取分布式锁
    String lockKey = "order_lock:" + getUserId();
    RLock lock = redissonClient.getLock(lockKey);
    
    try {
        if(lock.tryLock(50, 10000, TimeUnit.MILLISECONDS)) {
            return doCreateOrder();
        }
        throw new BusinessException("系统繁忙,请稍后再试");
    } finally {
        if(lock.isLocked() && lock.isHeldByCurrentThread()) {
            lock.unlock();
        }
    }
}

2.3.3 方案特点

  • 优点:双重保障、安全性最高
  • 缺点:实现复杂度最高

三、方案对比与选型建议

维度Token方案分布式锁方案双保险方案
实现复杂度★☆☆★★☆★★★
安全性★★☆★★★★★★
性能损耗5-10ms15-30ms20-50ms
适用场景常规业务场景高并发场景资金敏感型业务

选型建议

  1. 中小型系统优先选择Token方案
  2. 秒杀等高并发场景使用分布式锁
  3. 支付订单等关键业务使用双保险方案

四、生产环境注意事项

  1. Token安全增强

    • 采用加密Token(如JWT)
  2. 分布式锁优化

    // Redisson看门狗机制自动续期
    Config config = new Config();
    config.setLockWatchdogTimeout(30000); // 默认30秒
    
  3. 异常处理三原则

    • 网络异常必须重试解锁
    • 设置合理的锁超时时间
    • 记录锁竞争监控日志

相关文章:

  • doris:最佳实践
  • 网络安全等级保护基本要求、测评要求、高风险判定指引综合梳理
  • 最新智能优化算法: 中华穿山甲优化( Chinese Pangolin Optimizer ,CPO)算法求解23个经典函数测试集,MATLAB代码
  • GCD of Subset
  • 设计模式:代理模式
  • [250216] Fastfetch 2.36 版本发布 | Netrunner 25 “Shockworm” 正式发布!
  • 深入学习Linux命令行中的各种替换操作(命令替换、参数替换、进程替换)
  • 计算机网络原理试题三
  • 国产FPGA开发板选择
  • 04性能监控与调优篇(D5_JVM优化)
  • 物联网行业通识:从入门到深度解析
  • GitHub基本操作及Git简单命令
  • Code::Blocks 安装 一
  • 【人工智能】DeepSeek R1可以为我们做什么?
  • 贪吃蛇案例
  • Unity中如何判断URL是否为RTSP或RTMP流
  • 在 Linux 系统中,tc(Traffic Control) QoS 常用命令简介
  • 总线-AXI
  • 二分之一车辆模型研究不同参数下车辆对地面的动载荷和动载系数
  • 每日一题——兑换零钱(一)
  • 习近平复信中国丹麦商会负责人
  • 万科再获深铁集团借款,今年已累计获股东借款近120亿元
  • 车载抬头显示爆发在即?业内:凭借市场和产业链优势,国内供应商实现反超
  • 中国-拉共体成员国重点领域合作共同行动计划(2025-2027)
  • 75万采购防火墙实为299元路由器?重庆三峡学院发布终止公告:出现违法违规行为
  • 多省市已开展现房销售试点,去年全国现房销售面积占比超30%