什么是幂等性?四种接口幂等性方案详解!

什么是幂等性?四种接口幂等性方案详解!

幂等性在我们的工作中无处不在,无论是支付场景还是下订单等核心场景都会涉及,也是分布式系统最常遇到的问题,除此之外,也是大厂面试的重灾区。

知道了幂等性的重要性,下面我就详细介绍幂等性以及具体的解决方案,希望对大家有所帮助@mikechen

什么是幂等性

幂等是一个数学与计算机学概念,在数学中某一元运算为幂等时,其作用在任一元素两次后会和其作用一次的结果相同。

所谓接口幂等性,就是一次和多次请求某一个资源对于资源本身应该具有同样的结果。

什么是幂等性?四种接口幂等性方案详解!

也就是说,在接口重复调用的情况下,对系统产生的影响是一样的,这就是幂等性。

为什么需要幂等性

业务开发中,经常会遇到重复提交的情况,无论是由于网络问题无法收到请求结果而重新发起请求,或是前端的操作抖动而造成重复提交情况。

在交易系统,支付系统这种重复提交造成的问题有尤其明显,比如:用户在APP上连续点击了多次提交订单,后台应该只产生一个订单。

什么是幂等性?四种接口幂等性方案详解!

再比如:向支付宝发起支付请求,由于网络问题或系统BUG重试,支付宝应该只扣一次钱,而不是多次重试,造成多次扣钱。

什么是幂等性?四种接口幂等性方案详解!

再比如:现在是微服务的时代,服务化接口在外部调用者会存在多次调用的情况(考虑网络中断重试等),为了防止外部多次调用对系统数据状态的发生多次改变,将服务设计成幂等,就是为了防止多次重试,造成系统不一致的问题。

通过以上典型的支付场景就知道幂等性的重要性了,那问题来了,如何实现幂等性,有哪些解决方案?下面我们接着聊。

幂等性的解决方案

数据库唯一主键的实现主要是利用数据库中主键唯一约束的特性,一般来说唯一主键比较适用于”插入”时的幂等性,其能保证一张表中只能存在一条带该唯一主键的记录。

唯一索引 使用唯一索引可以避免脏数据的添加,当插入重复数据时数据库会抛异常,保证了数据的唯一性。

唯一索引表的创建示例如下:

<span class="hljs-keyword">CREATE&#xA0;<span class="hljs-keyword">TABLE&#xA0;<span class="hljs-string">table_name&#xA0;(
&#xA0;&#xA0;<span class="hljs-string">id&#xA0;<span class="hljs-built_in">int&#xA0;<span class="hljs-keyword">NOT&#xA0;<span class="hljs-literal">NULL&#xA0;AUTO_INCREMENT,
&#xA0;&#xA0;<span class="hljs-string">orderid&#xA0;<span class="hljs-built_in">varchar(<span class="hljs-number">32)&#xA0;<span class="hljs-keyword">NOT&#xA0;<span class="hljs-literal">NULL&#xA0;<span class="hljs-keyword">DEFAULT&#xA0;<span class="hljs-string">''&#xA0;<span class="hljs-keyword">COMMENT&#xA0;<span class="hljs-string">'&#x552F;&#x4E00;id',
&#xA0;&#xA0;PRIMARY&#xA0;<span class="hljs-keyword">KEY&#xA0;(<span class="hljs-string">id),
&#xA0;&#xA0;<span class="hljs-keyword">UNIQUE&#xA0;<span class="hljs-keyword">KEY&#xA0;<span class="hljs-string">uq_orderid&#xA0;(<span class="hljs-string">orderid)&#xA0;<span class="hljs-keyword">COMMENT&#xA0;<span class="hljs-string">'&#x552F;&#x4E00;&#x7EA6;&#x675F;'
)&#xA0;<span class="hljs-keyword">ENGINE=<span class="hljs-keyword">InnoDB;</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span>

使用数据库唯一主键完成幂等性时需要注意的是,该主键一般来说并不是使用数据库中自增主键,而是使用分布式 全局ID 充当主键,这样才能能保证在分布式环境下 ID 的全局唯一性。

适用操作:

  • 插入操作
  • 删除操作

数据库乐观锁方案一般只能适用于执行”更新操作”的过程,我们可以提前在对应的数据表中多添加一个字段,充当当前数据的版本标识。

这样每次对该数据库该表的这条数据执行更新时,都会将该版本标识作为一个条件,值为上次待更新数据中的版本标识的值。

<span class="hljs-keyword">select&#xA0;<span class="hljs-keyword">version&#xA0;<span class="hljs-keyword">from&#xA0;tablename&#xA0;<span class="hljs-keyword">where&#xA0;xxx
</span></span></span></span>

更新数据时首先和版本号作对比,如果不相等说明已经有其他的请求去更新数据了,提示更新失败。

<span class="hljs-keyword">update&#xA0;tablename&#xA0;<span class="hljs-keyword">set&#xA0;<span class="hljs-keyword">count=<span class="hljs-keyword">count+<span class="hljs-number">1,<span class="hljs-keyword">version=<span class="hljs-keyword">version+<span class="hljs-number">1&#xA0;<span class="hljs-keyword">where&#xA0;<span class="hljs-keyword">version=</span></span></span></span></span></span></span></span></span></span>

适用操作:

  • 更新操作

PRG 模式

Post/Redirect/Get 是一种 web 开发设计模式,用于防止表单的重复提交。

默认情况,提交 Post 请求到服务器后,如果直接刷新浏览器,会重新在提交一次 Post 请求。

什么是幂等性?四种接口幂等性方案详解!

在访问电商网站时,提交订单采用的是 Post 请求,如果直接刷新浏览器就容易导致重复订单的提交,这个不是用户希望发生的行为。

PRG 方法就是用户防止这种现象的发生,下面例图描述了用 PRG 方法来避免 Post 请求的重复提交。当服务器处理完 Post 请求后,会发响应给用户浏览器,指示用户浏览器用 Get 方式立刻访问另一条 URL 。用户浏览器拿到 Get 请求的数据,整个流程才算结束。

什么是幂等性?四种接口幂等性方案详解!

此时用户刷新当前页面,也不会引起 Post 请求的重复提交了。

针对客户端连续点击或者调用方的超时重试等情况,例如提交订单,此种操作就可以用 Token 的机制实现防止重复提交。

简单的说就是调用方在调用接口的时候先向后端请求一个全局 ID(Token),请求的时候携带这个全局 ID 一起请求(Token 最好将其放到 Headers 中),后端需要对这个 Token 作为 Key,用户信息作为 Value 到 Redis 中进行键值内容校验,如果 Key 存在且 Value 匹配就执行删除命令,然后正常执行后面的业务逻辑。

什么是幂等性?四种接口幂等性方案详解!

如果不存在对应的 Key 或 Value 不匹配就返回重复执行的错误信息,这样来保证幂等操作。

上面我只是列举了解决幂等性的解决方案与思路,其实还有很多类似解决方案,比如订单流程还可以结合前段拦截,以及更多的后端方案来保障唯一性。

这些还需要结合你的实际业务场景,来最终来选择更适合你的解决方案,但是万变不离其中,都是为了保证一次操作,保证唯一约束,这才是幂等性的本质。

以上!

作者简介

mikechen

,10年+大厂架构经验,《BAT架构技术500期》系列文章作者,曾就职于阿里、淘宝、百度等一线互联网大厂。

阅读mikechen的互联网架构更多技术文章合集
Java并发 |JVM |MySQL |Spring |Redis |分布式 |高并发 |架构师

Original: https://www.cnblogs.com/mikechenshare/p/16571394.html
Author: mikechen的互联网架构
Title: 什么是幂等性?四种接口幂等性方案详解!

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/617118/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • 使用java调用 salesforce SOAP API

    可以从github上下载最新版本然后用maven工具构建 下面列下我用wsc工具打成jar包测试过程中的代码: java -cp force-wsc-27.0.0-jar-with…

    Java 2023年6月7日
    051
  • Java内存问题分析与定位

    简介 JNI方法申请的native 内存,通常是在JDK库里;本地 C++ 方法直接通过 malloc申请的内存,不受JVM管控。 堆内内存: 指Java堆,GC算法管理的内存区域…

    Java 2023年5月29日
    092
  • ElasticSearch(一)

    官网: https://www.elastic.co/cn/elasticsearch/ 是什么? Elasticsearch 是一个分布式、RESTful 风格的搜索和数据分析引…

    Java 2023年6月8日
    084
  • Eureka详解系列(二)–如何使用Eureka(原生API,无Spring)

    简介 通过上一篇博客 Eureka详解系列(一)–先谈谈负载均衡器 ,我们知道了 Eureka 是什么以及为什么要使用它,今天,我们开始研究如何使用 Eureka。 在…

    Java 2023年6月13日
    077
  • Docker安装mysql

    [root@VM_177_101_centos xieshuang]# docker pull mysql:5.7.18 5.7.18: Pulling from library/…

    Java 2023年6月5日
    063
  • Nginx+Keepalived实现站点高可用

    http://seanlook.com/2015/05/18/nginx-keepalived-ha/ http://blog.csdn.net/conquer0715/artic…

    Java 2023年5月30日
    075
  • android多文件上传,java服务端接收

    Android多文件上传,java服务端接收 1、Android端 代码: String uploadUrl = "http://xxx/uploadFiles&quot…

    Java 2023年6月5日
    077
  • 【设计模式系列】结构型之桥接模式(常用)

    前言 不知道大家对于设计模式是个什么样的看法,是认为没必要啊,还是觉得是那种深入到骨子里的优雅。随着工作年限的增加,对设计模式愈发熟悉的前提下,真心觉得,设计模式是真他 * 的优雅…

    Java 2023年6月7日
    0115
  • 面向对象ooDay7

    .精华笔记:1)成员内部类: 应用率不高1.1)类中套类,外面的称为外部类,里面的称为内部类1.2)内部类通常只服务于外部类,对外不具备可见性1.3)内部类对象通常在外部类中创建1…

    Java 2023年6月13日
    052
  • json2string json格式到string的转换,调试有时候可以用到

    是别人写的,好久已经忘记出处了,贴这有时候会再用到。 function json2string(strObject) {var c, i, l, s =”, v, p;…

    Java 2023年6月13日
    055
  • CSS相关知识及入门

    修饰HTML页面,美化 CSS代码规范 CSS选择器 就是以HTML中的标签名作为选择器名称 选择CSS代码作用于对应标签名的标签上 适用于将相同样式作用于多个同名标签上 给相应的…

    Java 2023年6月6日
    068
  • mysql面试题整理

    1 myisam 和 innodb 引擎的区别 innodb 支持事务,外键,myisam 不支持 innodb 支持 mvcc ,myisam 不支持 innodb 支持表锁、行…

    Java 2023年6月5日
    0130
  • XWPFDocument创建和读取Office Word文档基础篇(一)

    注:有不正确的地方还望大神能够指出,抱拳了 老铁! 建议大家使用office word来创建文档。(wps和word结构有些不一样) IBodyElement —&#8…

    Java 2023年6月7日
    0107
  • MyBatis-Plus 笔记

    MyBatis-Plus学习(3.3.1.tmp版本教程) 1、快速开始 1.1、数据库脚本 DROP TABLE IF EXISTS user; CREATE TABLE use…

    Java 2023年6月7日
    086
  • 微服务开发框架 SpringCloud

    今天给大家介绍一下微服务开发框架 SpringCloud。 概述 微服务架构是当前软件开发领域的技术热点。它在各种博客、社交媒体和会议演讲上的出镜率非常之高。大家以前可能或多或少听…

    Java 2023年5月30日
    0109
  • Redis客户端连接远程Redis服务器失败解决百分百

    redis远程连接服务器失败,查看网上把 bind 127.0.0.1改了, protected-mode保护模式也关闭了, daemonize yes进程守护模式也关闭了但是还是…

    Java 2023年6月5日
    071
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球