如何保证接口幂等性,幂等性到底是干什么的

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
云数据库 Tair(兼容Redis),内存型 2GB
简介: 本文介绍了幂等性原则及其在程序中的应用。首先定义了幂等性,即无论执行多少次,结果不变的特性,并区分了幂等与非幂等操作。接着详细探讨了实现幂等性的策略,如使用唯一标识符、幂等性标记字段、乐观锁版本控制等。最后,通过Java示例展示了如何实现无状态幂等操作,并强调了幂等性在分布式系统和高并发场景下的重要性。

一、幂等性原则

1.1 幂等性的定义

  • 数学中:如果一个函数f满足f(f(x))=f(x),则称f是幂等的。
  • 程序中:如果一个操作对系统状态的影响,无论执行多少次,结果都是相同的,那么这个操作就是幂等的。

1.2 幂等性与非幂等性操作的区别

  • 幂等性操作的情况:
  1. GET请求:HTTP的GET请求是幂等的,无论调用多少次,服务器端的资源状态不会改变。
  2. DELETE请求:删除一个资源是幂等的,如果资源已经被删除,再次请求删除也不会改变资源状态。
  3. 数据库中的UPDATE语句:如果将某一列的值设置为固定的值,多次执行更新操作也会得到相同的结果。
  • 非幂等性操作的例子:
  1. POST请求:HTTP的POST请求通常是非幂等的,每次请求都会创建一个新的资源或修改现有资源的状态。
  2. 支付操作:多次执行支付操作可能会导致重复支付的情况,因此支付通常是非幂等性操作。
  3. 数据库中的INSERT操作:插入新记录是非幂等的,重复执行插入操作会导致多个记录被插入。
  • 区别总结:
  • 幂等性操作:多次执行操作得到的结果与执行一次相同,不会改变系统状态。
  • 非幂等性操作:多次执行操作可能会改变系统状态,结果不同于只执行一次操作。

二、程序中实现幂等性的策略

在程序中实现幂等性通常有以下几种基础策略:

  1. 唯一标识符(ID)
  • 为每个操作分配一个唯一的标识符,确保每个操作只能被执行一次。
  1. 幂等性标记字段(Idempotency Token)
  • 在每次执行操作时,传递一个幂等性标记字段到系统中。系统在接收到请求后,首先检查该标记字段是否已经被使用过,如果已经被使用过则不执行操作。
  1. 乐观锁版本控制
  • 针对需要幂等性的操作,可以引入版本控制机制。每次执行操作时,需要提供当前版本号,系统根据版本号判断是否执行操作
  1. 状态检查
  • 在执行操作之前,先检查系统的状态是否已经处于预期状态。如果系统已经处于预期状态,则操作可以执行;否则,不执行操作
  1. 事务管理
  • 使用数据库事务来保证操作的原子性,如果操作失败,事务可以回滚到操作前的状态。
  1. 悲观锁
  • 在操作开始时锁定资源,直到操作完成才释放资源,防止其他操作干扰。

当然,实际程序开发过程中还有许多别的方法,我们要合理的选型,方能写出健壮的代码。

三、干货:Java中实现一个无状态的幂等操作

在Java中实现无状态的幂等操作通常意味着操作不依赖于任何外部状态,并且每次执行的结果都是一致的。下面跟着我一起来完成。

#bytemd-mermaid-1728963583449-0{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#bytemd-mermaid-1728963583449-0 .error-icon{fill:#552222;}#bytemd-mermaid-1728963583449-0 .error-text{fill:#552222;stroke:#552222;}#bytemd-mermaid-1728963583449-0 .edge-thickness-normal{stroke-width:2px;}#bytemd-mermaid-1728963583449-0 .edge-thickness-thick{stroke-width:3.5px;}#bytemd-mermaid-1728963583449-0 .edge-pattern-solid{stroke-dasharray:0;}#bytemd-mermaid-1728963583449-0 .edge-pattern-dashed{stroke-dasharray:3;}#bytemd-mermaid-1728963583449-0 .edge-pattern-dotted{stroke-dasharray:2;}#bytemd-mermaid-1728963583449-0 .marker{fill:#333333;stroke:#333333;}#bytemd-mermaid-1728963583449-0 .marker.cross{stroke:#333333;}#bytemd-mermaid-1728963583449-0 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#bytemd-mermaid-1728963583449-0 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#bytemd-mermaid-1728963583449-0 .cluster-label text{fill:#333;}#bytemd-mermaid-1728963583449-0 .cluster-label span{color:#333;}#bytemd-mermaid-1728963583449-0 .label text,#bytemd-mermaid-1728963583449-0 span{fill:#333;color:#333;}#bytemd-mermaid-1728963583449-0 .node rect,#bytemd-mermaid-1728963583449-0 .node circle,#bytemd-mermaid-1728963583449-0 .node ellipse,#bytemd-mermaid-1728963583449-0 .node polygon,#bytemd-mermaid-1728963583449-0 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#bytemd-mermaid-1728963583449-0 .node .label{text-align:center;}#bytemd-mermaid-1728963583449-0 .node.clickable{cursor:pointer;}#bytemd-mermaid-1728963583449-0 .arrowheadPath{fill:#333333;}#bytemd-mermaid-1728963583449-0 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#bytemd-mermaid-1728963583449-0 .flowchart-link{stroke:#333333;fill:none;}#bytemd-mermaid-1728963583449-0 .edgeLabel{background-color:#e8e8e8;text-align:center;}#bytemd-mermaid-1728963583449-0 .edgeLabel rect{opacity:0.5;background-color:#e8e8e8;fill:#e8e8e8;}#bytemd-mermaid-1728963583449-0 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#bytemd-mermaid-1728963583449-0 .cluster text{fill:#333;}#bytemd-mermaid-1728963583449-0 .cluster span{color:#333;}#bytemd-mermaid-1728963583449-0 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#bytemd-mermaid-1728963583449-0 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#bytemd-mermaid-1728963583449-0 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}

不存在

存在

定义服务类

使用线程安全的缓存

执行操作的方法

生成唯一操作标识符

检查缓存

执行实际的操作逻辑

存储操作结果到缓存

返回操作结果

下面来一个实现的类瞧瞧:

java

代码解读

复制代码

import java.util.concurrent.ConcurrentHashMap;
import java.util.UUID;

public class IdempotentService {

    /**
     * 使用线程安全的缓存来存储操作结果
     */
    private ConcurrentHashMap<String, Object> cache = new ConcurrentHashMap<>();

    public Object executeOperation(Object... parameters) {
        // 生成全局唯一的操作标识符...这里只是案例,实际这个唯一生成的要分业务去处理
        String operationId = UUID.randomUUID().toString();

        // 检查操作是否已经执行过
        if (cache.containsKey(operationId)) {
            // 操作已执行,直接返回缓存的结果
            return cache.get(operationId);
        }

        // 执行操作
        Object result = performOperation(parameters);

        // 将结果存储到缓存中
        cache.put(operationId, result);

        return result;
    }

    private Object performOperation(Object[] parameters) {
        // 执行具体的操作逻辑
        // ...
        return "Operation Result";
    }
}

四、总结

幂等性在编码中的重要性在于确保即使在分布式系统高并发场景下,重复的请求或操作也不会导致不一致或意外的结果,从而保障系统的稳定性和数据的准确性。

程序员应该深刻理解幂等性原理,并在设计和实现系统功能时主动考虑和应用幂等性策略,以确保系统的健壮性和用户的信赖度。


转载来源:https://juejin.cn/post/7402204174065139739

相关文章
|
SQL 缓存 NoSQL
接口的幂等性设计和防重保证,详细分析幂等性的几种实现方法
本篇文章详细说明了幂等性,解释了什么是幂等性,幂等性的使用场景,讨论了幂等和防重的概念。分析了幂等性的情况以及如何设计幂等性服务。阐述了幂等性实现防重的几种策略,包括乐关锁,防重表,分布式锁,token令牌以及支付缓冲区。
6693 0
接口的幂等性设计和防重保证,详细分析幂等性的几种实现方法
|
6月前
|
存储 缓存 安全
接口的幂等性
接口的幂等性
71 0
|
18天前
|
设计模式 缓存 前端开发
什么是幂等性?四种接口幂等性方案详解!
本文深入分布式系统中的幂等性问题及其解决方案,涵盖数据库唯一主键、乐观锁、PRG模式和防重Token等方法,关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
什么是幂等性?四种接口幂等性方案详解!
|
1月前
|
数据库
什么是接口幂等性?如何保证接口幂等性?
接口幂等性(Idempotency)是指同样的请求被重复执行多次,产生的结果与执行一次的结果相同。换句话说,接口无论被调用一次还是多次,系统的最终状态保持不变。
105 5
|
3月前
|
SQL 前端开发 NoSQL
关于幂等:大厂如何解决幂等问题?
为确保分布式系统中接口的幂等性,防止重复下单及更新数据时出现ABA问题,可采取以下措施:首先,每个请求需具备唯一标识符,如订单ID,确保同一订单ID仅能成功处理一次。其次,处理请求后需记录状态标识,如在数据库中记录支付流水。接收请求时检查是否已处理,利用数据库的唯一性约束防止重复操作。例如,支付前插入支付流水记录,若订单ID已存在,则阻止重复支付。此外,为解决ABA问题,可在订单表中增加版本号字段,更新数据时需验证版本号一致性并同步递增版本号,确保数据正确性及更新操作的幂等性。
|
3月前
|
SQL 索引
分布式之接口幂等性
分布式之接口幂等性
46 2
|
5月前
|
数据库 API 网络架构
浅谈应用接口的幂等性
【6月更文挑战第2天】本文介绍幂等性是计算和网络通信中的重要概念,确保同一操作执行多次不会改变结果。在数据库操作中,查询、删除(同一数据)和特定更新是幂等的,而插入和累加更新不是。幂等性和安全性(如GET、HEAD等方法)确保多次请求无副作用,对涉及金钱的操作尤为重要。
73 0
|
6月前
|
消息中间件 关系型数据库 MySQL
如何保证消息幂等
如何保证消息幂等
76 0
|
SQL NoSQL Java
【项目场景】如何保证接口的幂等性?
【项目场景】如何保证接口的幂等性?
456 0
|
消息中间件 SQL 缓存
接口幂等性
接口幂等性 一、定义