保证接口幂等性的多种实现方式(数据库方案)

news2024/11/26 23:49:19

1. 幂等性的概念

        接口幂等性是指在软件工程和Web服务领域中,一个接口(通常是HTTP API)无论被调用一次还是多次,其对系统产生的副作用应该是相同的,即结果保持一致,不会因为多次请求而有所不同。换句话说,多次执行同一操作应当产生与执行一次相同的效果,不会额外改变系统的状态。

2. 幂等性的核心价值

确保数据一致性:在存在网络延迟或不稳定的情况下,请求可能被重复发送。幂等性确保即使请求多次到达服务器,也不会导致多次创建资源、多次扣除账户余额等错误,从而维护了数据的一致性和完整性。

简化错误处理:客户端可以更简单地处理请求失败的情况,只需重试即可,无需复杂的逻辑来判断是否需要重试或如何处理潜在的副作用。

提升用户体验:用户操作(如点击支付按钮)因网络问题或误操作导致的重复提交,不会引起多次扣款等不良后果,增强了用户对系统的信任感。

3. 幂等性与HTTP方法

请求类型安全性与幂等性描述
GET安全且幂等用于获取资源,多次请求应返回相同的结果
PUT不安全但幂等用于替换整个资源。无论PUT操作执行多少次,资源最终状态都是一样的,即被最后的请求体内容所替换
POST不安全且不幂等用于创建新的资源,多次调用可能会创建多个资源
DELETE不安全但幂等重复提交,删除一个已经不存在的资源,不会改变系统状态

        其中POST是非幂等的,因为它用于创建新的资源,多次调用可能会创建多个不同的资源。但在某些设计中,如果POST请求设计为总是创建相同的结果(基于请求数据和当前系统状态),也可以实现幂等性。

4. 幂等性的应用场景

        幂等性对于保证系统的一致性和可靠性至关重要,尤其是在分布式系统和网络不稳定环境下,它有助于处理如下几种常见场景:

  • 网络重传:在网络不稳定的情况下,请求可能会被重传,幂等性确保重传不会导致多次执行操作,如多次扣款。
  • 用户误操作:用户可能因页面刷新、误点击等原因重复提交请求,幂等性保护用户免受因此导致的数据不一致影响。
  • 用户恶意刷单:比如在抢兑换码、投票这种互动中,可能会有用户会进行恶意的重复发送请求,恶意刷单,使结果不实。
  • 异步消息重复处理:在使用消息队列或事件驱动架构时,消息可能因故障恢复机制被重新投递,幂等性处理可以避免业务逻辑被重复执行

5. 解决方案

保证接口幂等性有多种方法,当前提供数据库方案,如下:

5.1. 数据库唯一索引

这可以算是最简单的方法了,直接在数据库表中的某个关键字段设置唯一索引,下面以订单(order)数据库表为例写一段SQL:

alter table `order` add UNIQUE KEY `t_xxx` (`某个字段`); 

加了唯一索引之后,第一次请求数据可以插入成功。但后面的相同请求,插入数据时会报异常,表示唯一索引有冲突:

Duplicate entry '002' for key 'order.t_code

具体流程图如下:

5.2. 建立防重表

        有同学可能就问了,上面的方案不太合理,因为有时候我们的表中需要一些重复数据,只有一些特殊场景才不需要重复数据,唯一索引方案可能就不合适了。

        这个时候可以试试防重表,简单来说就是我们再单独建立一张表,只需要含有id和想要唯一的索引字段。

具体流程图如下:

5.3. 悲观锁机制

        悲观锁机制可以作为一种手段来帮助解决接口幂等性问题,尤其是在处理高并发场景下对数据的并发修改需求。悲观锁的基本假设是数据在并发访问期间很可能发生冲突,因此在事务开始时就立即锁定所需的数据资源,防止其他事务对其进行修改,直到当前事务结束。

        以下是利用MySQL悲观锁机制解决接口幂等性的基本方案:

1. 使用SELECT ... FOR UPDATE

        在执行更新操作之前,先使用SELECT ... FOR UPDATE语句锁定要修改的行。这会在读取数据的同时加上排他锁(X锁),确保其他事务无法修改这些数据,直到当前事务结束(提交或回滚)。

START TRANSACTION;

SELECT * FROM your_table WHERE id = ? FOR UPDATE;

-- 根据查询结果判断是否需要更新
IF (需要更新) THEN
    UPDATE your_table SET column=value WHERE id = ?;
END IF;

COMMIT;

2. 结合接口幂等性设计

结合上述SQL操作,可以设计一个幂等性接口处理流程:

        大缺点:悲观锁需要在同一个事务操作过程中锁住一行数据,如果事务耗时比较长,会造成大量的请求等待,影响接口性能。

5.4. 乐观锁机制

        悲观锁会增加锁争用的可能性,可能导致事务等待和阻塞,影响系统性能,特别是在高并发场景下。因此,应谨慎使用,乐观锁某些情况下就是个很好的替代方案。

        MySQL乐观锁机制是一种非阻塞的并发控制策略,它假定多线程同时修改数据的概率较低,因此不会在事务一开始就对数据加锁,而是在更新数据时检查数据是否被其他事务修改过。这对于高并发场景下解决接口幂等性问题特别有效,因为它减少了锁的竞争,提高了系统的吞吐量。以下是利用MySQL乐观锁机制解决接口幂等性的方案:

1. 版本字段实现乐观锁

在数据库表中添加一个额外的字段作为版本控制,比如version字段,初始值为1。

CREATE TABLE your_table (
    id INT PRIMARY KEY,
    data VARCHAR(100),
    version INT DEFAULT 1
);

2. 接口调用流程

客户端请求:客户端发出修改数据的请求,请求中包含数据的原始版本号(如果有的话)。

读取数据并附带版本信息:服务端首先查询需要更新的数据,并获取其当前的版本号。

SELECT * FROM your_table WHERE id = ?;

 幂等性检查与更新:在更新数据时,同时在UPDATE语句中加入版本号的条件检查,确保只有当版本号与查询时一致时才执行更新。

   UPDATE your_table 
   SET data = ?, version = version + 1 
   WHERE id = ? AND version = ?;

---(data = ? 是要更新的新数据值。
---version = version + 1 表示更新成功后,版本号递增。
---WHERE id = ? AND version = ? 确保只有当记录的版本号与预期一致时才执行更新。)

④ 结果判断:根据UPDATE语句影响的行数判断是否更新成功。

如果影响行数为1,说明更新成功,且数据没有被其他事务修改过。
如果影响行数为0,说明数据在执行更新前已经被其他事务修改,此时可以根据业务逻辑选择重试或返回错误信息。

具体流程图如下:

今天写到这里,明天再来写token方案哈。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1631783.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

ES练习项目-酒店搜索

目录 1 需求分析2 酒店搜索和分页2.1 请求和响应分析2.2 定义实体类,接收请求参数的JSON对象2.3 编写controller,接收页面的请求2.4 编写业务实现,利用RestHighLevelClient实现搜索、分页 3. 酒店结果过滤3.1 请求和响应分析3.2 修改请求参数…

上位机图像处理和嵌入式模块部署(树莓派4b设置ftp下载)

【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing 163.com】 作为一个开发板,最好支持ftp下载,这样文件的上传和下载都会比较方便。虽然目前为止,利用mobaxterm和ssh也能实现…

算法学习(5)-图的遍历

目录 什么是深度和广度优先 图的深度优先遍历-城市地图 图的广度优先遍历-最少转机 什么是深度和广度优先 使用深度优先搜索来遍历这个图的过程具体是: 首先从一个未走到过的顶点作为起始顶点, 比如以1号顶点作为起点。沿1号顶点的边去尝试访问其它未…

用Jenkins实现cherry-pick多个未入库的gerrit编译Android固件

背景: 在做Android固件开发的时候,通常我们可以利用gerrit-trigger插件,开发者提交一笔的时候自动触发jenkins编译,如果提交的这一笔的编译依赖其他gerrit才能编译过,我们可以在commit message中加入特殊字段,让jenkins在编译此笔patch的时候同时抓取依赖的gerrit代码下…

selenium在Pycharm中结合python的基本使用、交互、无界面访问

下载 下载与浏览器匹配的浏览器驱动文件,这里一定注意的是,要选择和浏览器版本号相同的驱动程序,否则后面会有很多问题。 (1)浏览器(以google为例)版本号的查询: 我这里的版本号是1…

RT-Thread V5.2.0版本尝鲜

文章目录 配置界面的更新新旧内核生成的二进制文件大小差异旧版本V5.1.0内核旧版本V5.2.0内核 配置界面的更新 尝试将手头RT-Thread工程的OS部分源码进行了更新,发现不少新的变化 配置界面变得更醒目: 配置变更保存提醒界面更新: 新旧内核…

Android Widget开发代码示例详细说明

因为AppWidgetProvider扩展自BroadcastReceiver, 所以你不能保证回调函数完成调用后,AppWidgetProvider还在继续运行。 a. AppWidgetProvider 的实现 /*** Copyright(C):教育电子有限公司 * Project Name: NineSync* Filename: SynWidgetProvider.java * Author(S…

【Node.js工程师养成计划】之原生node开发web服务器

一、使用node创建http服务器 var http require(http);// 获取到服务器实例对象 var server http.createServer() server.listen(8080, function() {console.log(http://127.0.0.1:8080); })server.on(request, function(req, res){console.log(request);res.write(6666666688…

VitePress 构建的博客如何部署到 github 平台?

VitePress 构建的博客如何部署到 github 平台? 1. 新建 github 项目 2. 构建 VitePress 项目 2.1. 设置 config 中的 base 由于我们的项目名称为 vite-press-demo,所以我们把 base 设置为 /vite-press-demo/,需注意前后 / export default…

【数据结构与算法(C语言)】1. 线性表的顺序存储

文章目录 前言一. 线性表插入和删除1. 元素的插入2. 元素的删除 二. 代码三. 优缺点 前言 线性表的顺序存储结构,指的是用一段地址连续的存储单元依次存储线性表的数据结构 一. 线性表插入和删除 1. 元素的插入 插入位置之后的数据都向后移一位,上图中元…

chrome 安装devtools

chrome 安装devtools 下载安装 链接:https://github.com/vuejs/devtools 选择对应版本: 安装yarn 下载 npm install -g yarn --registryhttps://registry.npmmirror.com进入下载的目录安装依赖 yarn install --registryhttps://registry.npmmirror.…

ASP.NET汽车销售管理系统的设计与开发

摘 要 随着人们生活水平的不断提高,人们对汽车的消费和需求也越来越旺盛。很多汽车销售公司的业务环节仍然运用人工记账的传统方法,既容易出错又会导致账目混乱,查询和统计起来也非常不方便,费时又费力,严重时会给公…

stm32单片机开发二、定时器-内部时钟中断和外部时钟中断、编码器

定时器本质就是一个计数器 案例:定时器定时中断 内部时钟中断 Timer_Init(); //定时中断初始化 /*** 函 数:定时中断初始化* 参 数:无* 返 回 值:无*/ void Timer_Init(void) {/*开启时钟*/RCC_APB1PeriphClockCmd(RCC…

CSS-复合选择器

作用&#xff1a; 后代选择器&#xff1a; 子代选择器 并集选择器 用逗号隔开&#xff0c;在style里面写的时候&#xff0c;每一个标签空一行。 <title>Document</title><style>p,div,span{color: aqua;}</style> </head> <body><p>…

在Linux操作系统中关于磁盘(硬盘)管理的操作

电脑中数据存储设备&#xff1a;硬盘&#xff08;实现数据的持久化存储&#xff09;&#xff0c;内存 在Linux操作系统中一切皆文件的思想&#xff0c;所有的设备在Linux操作系统中都是通过文件来标识的&#xff0c;所以每一个硬盘都对应一个块设备文件。 在Linux操作系统中所…

Golang | Leetcode Golang题解之第55题跳跃游戏

题目&#xff1a; 题解&#xff1a; // 贪心算法 func canJump(nums []int) bool {cover : 0n : len(nums)-1for i : 0; i < cover; i { // 每次与覆盖值比较cover max(inums[i], cover) //每走一步都将 cover 更新为最大值if cover > n {return true}}return false } …

YOLov5 + Gradio搭建简单的Web GUI

写在前面&#xff1a;当我们将模型训练出来了&#xff0c;此时就需要做UI界面给别人展示了。python提供的Gradio可以快速的搭建web页面。生成本地网址和公网网址&#xff0c;方面自己测试和用户测试。 一、安装 Gradio介绍 Gradio是一个开源的python库&#xff0c;用于构建机…

深度学习模型Deep Learning Model

什么是深度学习&#xff1f;&#xff1f; 深度学习模型是一种基于人工神经网络&#xff08;Artificial Neural Networks, ANN&#xff09;的机器学习模型&#xff0c;其核心思想是通过多层次的神经网络结构来学习数据的特征表示和模式。这些模型通常由多个层次&#xff08;深度…

WPS的JS宏如何设置Word文档的表格的单元格文字重新编号

希望对Word文档中的表格进行统一处理&#xff0c;表格内的编号&#xff0c;有时候会出现紊乱&#xff0c;下一个表格的编号承接了上一个表格的编号&#xff0c;实际需要重新编号。 当表格比较多时&#xff0c;手动更改非常麻烦&#xff0c;而且更改一遍并不能完成&#xff0c;…

测算sample gpt

测算代码 import pandas as pd import matplotlib.pyplot as pltlosspd.read_pickle("loss_8.pkl") plt.plot(loss) losspd.read_pickle("loss_16.pkl") plt.plot(loss) losspd.read_pickle("loss_4_8.pkl") plt.plot(loss) losspd.read_pickle(…