砍材农夫砍材农夫
  • 微信记账小程序
  • java
  • redis
  • mysql
  • 场景类
  • 框架类
  • vuepress搭建
  • hexo搭建
  • 云图
  • 常用工具

    • git
    • gradle
    • Zadig
    • it-tools
    • 开源推荐
    • curl
  • 大前端

    • nodejs
    • npm
    • webpack
    • 微信
    • 正则
    • uniapp
  • java

    • java基础
    • jdk体系
    • jvm
    • spring
    • spring_cloud
    • spring_boot
    • 分库分表
    • zookeeper
  • python

    • python基础
    • python高级
    • python框架
  • 算法

    • 算法
  • 网关

    • spring_cloud_gateway
    • openresty
  • 高可用

    • 秒杀
    • 分布式
    • 缓存一致
  • MQ

    • MQ
    • rabbitMQ
    • rocketMQ
    • kafka
  • 其它

    • 设计模式
    • 领域驱动(ddd)
  • 关系型数据库

    • mysql5.0
    • mysql8.0
  • 非关系型数据库

    • redis
    • mongoDB
  • 分布式/其他

    • ShardingSphere
    • 区块链
  • 向量数据库

    • M3E
    • OPEN AI
  • Jmeter
  • fiddler
  • wireshark
  • AI入门
  • AI大模型
  • AI插件
  • AI集成框架
  • 相关算法
  • AI训练师
  • 量化交易
  • gitee
  • github
  • infoq
  • osc
  • 砍材工具
  • 关于
  • 相关运营
  • docker
  • k8s
  • devops
  • nginx
  • 元宇宙
  • 区块链
  • 物联网
  • linux
  • webrtc
  • web3.0
  • gitee
  • github
  • infoq
  • osc
  • 砍材工具
  • 关于
  • 中考
  • 投资
  • 保险
  • 思
  • 微信记账小程序
  • java
  • redis
  • mysql
  • 场景类
  • 框架类
  • vuepress搭建
  • hexo搭建
  • 云图
  • 常用工具

    • git
    • gradle
    • Zadig
    • it-tools
    • 开源推荐
    • curl
  • 大前端

    • nodejs
    • npm
    • webpack
    • 微信
    • 正则
    • uniapp
  • java

    • java基础
    • jdk体系
    • jvm
    • spring
    • spring_cloud
    • spring_boot
    • 分库分表
    • zookeeper
  • python

    • python基础
    • python高级
    • python框架
  • 算法

    • 算法
  • 网关

    • spring_cloud_gateway
    • openresty
  • 高可用

    • 秒杀
    • 分布式
    • 缓存一致
  • MQ

    • MQ
    • rabbitMQ
    • rocketMQ
    • kafka
  • 其它

    • 设计模式
    • 领域驱动(ddd)
  • 关系型数据库

    • mysql5.0
    • mysql8.0
  • 非关系型数据库

    • redis
    • mongoDB
  • 分布式/其他

    • ShardingSphere
    • 区块链
  • 向量数据库

    • M3E
    • OPEN AI
  • Jmeter
  • fiddler
  • wireshark
  • AI入门
  • AI大模型
  • AI插件
  • AI集成框架
  • 相关算法
  • AI训练师
  • 量化交易
  • gitee
  • github
  • infoq
  • osc
  • 砍材工具
  • 关于
  • 相关运营
  • docker
  • k8s
  • devops
  • nginx
  • 元宇宙
  • 区块链
  • 物联网
  • linux
  • webrtc
  • web3.0
  • gitee
  • github
  • infoq
  • osc
  • 砍材工具
  • 关于
  • 中考
  • 投资
  • 保险
  • 思
  • 常见案例分析

    • 分布式ID
    • 分布式锁
    • 订单超时取消
    • 库存扣减问题
    • 幂等接口设计
    • 接口限流设计
    • 接口防刷设计
    • 多级缓存设计
  • 相关拓展知识

    • TCP和UDP区别
    • 签名算法
    • 身份认证令牌
    • 如何防止class类被反编译
    • 消息队列
    • maven如何统一指定jdk
    • maven常用插件
  • 算法|数据结构

    • 二叉树
    • 红黑树
    • 快速比较两棵树查找相同节点方法
  • 幂等接口设计
  • 常见策略
    • 唯一索引/约束
    • 去重表(配合唯一索引)
    • 状态机幂等
    • Token 机制(适用于防止重复提交)
    • 分布式锁(Redis/ Zookeeper)
  • 总结

幂等接口设计

  • 网络重试

客户端因超时重试导致请求重复提交

  • 消息重复

消息队列中间件可能重复投递消息

  • 用户误操作

用户多次点击提交按钮

  • 系统容错

分布式系统依赖重试保证最终一致性,幂等性是基础

常见策略

唯一索引/约束

利用数据库的唯一索引防止重复数据插入。
适用于创建业务单据(如订单号、支付流水号唯一)
CREATE TABLE `order` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `order_no` varchar(64) NOT NULL COMMENT '订单号',
  `status` tinyint(4) DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_order_no` (`order_no`)
) ENGINE=InnoDB;

去重表(配合唯一索引)

使用独立的去重表记录已处理的请求标识,利用数据库唯一约束实现幂等
@Transactional
public void processOrder(Request request) {
    String requestId = request.getRequestId();
    // 插入去重记录,利用数据库唯一约束
    try {
        deduplicationDao.insert(requestId);
    } catch (DuplicateKeyException e) {
        // 已处理,直接返回或抛出异常
        return;
    }
    // 执行实际业务逻辑
    orderDao.create(request.getOrder());
}

状态机幂等

对于有状态变更的业务(如订单状态流转),通过限制状态转移方向实现幂等
public boolean payOrder(String orderId) {
    Order order = orderDao.selectByOrderId(orderId);
    if (order.getStatus() == OrderStatus.PENDING_PAY) {
        order.setStatus(OrderStatus.PAID);
        orderDao.update(order);
        return true;
    }
    // 已经支付过了,视为成功但不再重复处理
    return false;
}

Token 机制(适用于防止重复提交)

服务端生成唯一token下发到客户端(如表单隐藏域)

// 生成token
public String generateToken(String userId) {
    String token = UUID.randomUUID().toString();
    redisTemplate.opsForValue().set(TOKEN_PREFIX + userId, token, 30, TimeUnit.MINUTES);
    return token;
}

// 执行业务前校验token
public boolean checkAndRemoveToken(String userId, String token) {
    String key = TOKEN_PREFIX + userId;
    String storedToken = redisTemplate.opsForValue().get(key);
    if (token.equals(storedToken)) {
        redisTemplate.delete(key);
        return true;
    }
    return false;
}

分布式锁(Redis/ Zookeeper)

public void handleRequest(String orderId) {
    String lockKey = "lock:order:" + orderId;
    boolean locked = redisLock.tryLock(lockKey, 10, TimeUnit.SECONDS);
    if (!locked) {
        // 未获取到锁,可能是重复请求,直接返回或稍后重试
        return;
    }
    try {
        // 检查是否已处理(结合去重表)
        if (processedChecker.isProcessed(orderId)) {
            return;
        }
        // 业务处理
        doBusiness(orderId);
        // 标记已处理
        processedChecker.markProcessed(orderId);
    } finally {
        redisLock.unlock(lockKey);
    }
}

总结

新增数据:唯一索引、去重表
状态变更:状态机、乐观锁
防止重复提交:Token、分布式锁
通用方案:幂等键+存储去重+结果缓存
最近更新: 2026/3/1 14:43
Contributors: kcnf
Prev
库存扣减问题
Next
接口限流设计