分布式锁和数据库锁完成接口幂等性

news2025/6/4 19:07:32

1、分布式锁

唯一主键与乐观锁的本质是使用了数据库的锁,但由于数据库锁的性能不太好,所以我们可使用Redis、Zookeeper等中间件来实现分布式锁的功能,以Redis为例实现幂等:当用户通过浏览器发起请求,服务端接收到请求后,使用唯一标识(如订单号)作为Redis的key。然后使用Redis的set命令,将该唯一标识存储到Redis中并设置超时时间,业务根据Redis返回的结果做不同的处理:
(1)如果保存Redis成功,那么允许当前的线程执行业务操作。
(2)若保存Redis失败,说明是重复请求,则直接响应客户端,请求处理成功。
在分布式锁中要设置一个合理的过期时间,如果设置过短,无法有效的防止重复请求;如果设置过长,占用了Redis的存储空间,在请求非常多的情况下会给Redis造成压力。
在这里插入图片描述

2、状态机机制

在业务表中有状态的时候,如订单表中的订单状态(待提交、待支付、待发货、待收货等等)这些状态的值是有规律的,按照业务节点一级级的流转,那么我们就能利用这个特性实现接口的幂等,假如订单id为order_abc12356的订单当前状态是待支付,当用户支付后,订单的状态要变成待发货,更新的语句如下:

update order set status = 2 where order_id =order_abc12356 and status = 1 

线程T1请求时,该订单的状态是待支付(status = 1),所以该update语句可以正常更新数据,sql执行结果的影响行数是1,订单状态变成了2。线程T2相同的请求过来,再执行相同的sql时,由于订单状态变成了2,再用status=1作为条件,无法查询出需要更新的数据,所以最终sql执行结果的影响行数是0,即不会真正的更新数据。数据表记录中的状态来作为条件做更新其实跟乐观锁使用版本号类似。
在这里插入图片描述

3、数据库悲观锁

假设我们查询到某个订单A后,然后更新订单的状态,此时就可以使用数据库的悲观锁实现。使用悲观锁可以添加for update关键字,即对这行记录上锁,上行锁还是表锁取决于where后面的查询字段索引的类型,假设订单的id是唯一主键,那么就是行锁,可以使用sql查询

select * from order where order_id = 具体id  for update

若是线程T1执行了select … for update,此时就会对这行记录上锁了,那么直到整个线程T1提交事务之前,T2线程来查询相同的订单id数据会进入到阻塞状态。当T1完成业务处理之后释放锁,其他的线程才可以继续操作这条数据。悲观锁在同一事务操作过程中锁住了一行数据,别的请求过来只能等待,如果当前事务耗时比较长,就很影响接口性能。对于Mysql数据库,要求存储引擎必须用innodb,因为innodb才支持事务,另外orderId字段一定要是主键或者唯一索引,不然会锁整张表。:
在这里插入图片描述

4、数据库乐观锁

数据库乐观锁方案一般适用于执行"更新操作"的过程,我们可以提前在对应的数据表中额外添加一个字段来充当数据的版本标识。这样每次对该数据表的这条数据执行更新时,都会将该版本标识作为一个条件,值为上次待更新数据中的版本标识的值,每次更新的时候,我们使用版本号来进行字段校验以及进行update更新

UPDATE order SET status=1,version=version+1 WHERE id=id值 AND version=0;

在WHERE后面的条件id=id值AND version=0 被执行后,id=id值 的 version被更新为1,所以如果重复执行该条sql语句将不生效,因为id=id值 AND version=0的数据已经不存在,通过这样方式就能保住更新的幂等,多次更新对结果不会产生影响
在这里插入图片描述

5、数据库唯一主键

数据库唯一主键的实现原理是使用数据库中主键唯一约束的特性,一般来说唯一主键比较适用于添加数据时的幂等性场景,唯一主键能保证一张表中只能存在一条该唯一主键记录,使用数据库唯一主键实现接口幂等性时需要注意的是,为了保证在分布式环境下ID的全局唯一性,这里的主键一般使用分布式ID充当主键:在这里插入图片描述

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

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

相关文章

浅谈JMeter之常见问题Address already in use: connect

浅谈JMeter之常见问题Address already in use: connect 在JMeter高并发测试中出现“address already in use”错误,主要源于Windows系统的TCP端口资源耗尽及连接配置问题,在执行JMeter中查看结果树 原因分析 GET请求默认采用短连接(Conne…

【机器学习基础】机器学习入门核心算法:随机森林(Random Forest)

机器学习入门核心算法:随机森林(Random Forest) 1. 算法逻辑2. 算法原理与数学推导2.1 核心组件2.2 数学推导2.3 OOB(Out-of-Bag)误差 3. 模型评估评估指标特征重要性可视化 4. 应用案例4.1 医疗诊断4.2 金融风控4.3 遥…

【深度学习】12. VIT与GPT 模型与语言生成:从 GPT-1 到 GPT4

VIT与GPT 模型与语言生成:从 GPT-1 到 GPT4 本教程将介绍 GPT 系列模型的发展历程、结构原理、训练方式以及人类反馈强化学习(RLHF)对生成对齐的改进。内容涵盖 GPT-1、GPT-2、GPT-3、GPT-3.5(InstructGPT)、ChatGPT …

常规算法学习

算法 1. 排序算法1. 归并排序1.1 普通归并排序1.2 优化后的归并排序(TimSort) 2. 插入排序2.1 直接插入排序2.2 二分插入排序2.3 成对插入排序 3. 快速排序3.1 单轴快速排序3.2 双轴快排 4. 计数排序 2. 树1. 红黑树(Red Black Tree&#xff…

Google 发布的全新导航库:Jetpack Navigation 3

前言 多年来,Jetpack Navigation 库一直是开发者的重要工具,但随着 Android 用户界面领域的发展,特别是大屏设备的出现和 Jetpack Compose 的兴起,Navigation 的功能也需要与时俱进。 今年的 Google I/O 上重点介绍了 Jetpack Na…

Arbitrum Stylus 合约实战 :Rust 实现 ERC20

在《Arbitrum Stylus 深入解析与 Rust 合约部署实战》篇中,我们深入探讨了 Arbitrum Stylus 的核心技术架构,包括其 MultiVM 机制、Rust 合约开发环境搭建,以及通过 cargo stylus 实现简单计数器合约的部署与测试。Stylus 作为 Arbitrum Nitr…

内存管理--《Hello C++ Wrold!》(8)--(C/C++)--深入剖析new和delete的使用和底层实现

文章目录 前言C/C内存分布new和deletenew和delete的底层定位new表达式 内存泄漏作业部分 前言 在C/C编程中,内存管理是理解程序运行机制的核心基础,也是开发高效、稳定程序的关键。无论是局部变量的存储、动态内存的分配,还是对象生命周期的…

Java进阶---JVM

JVM概述 JVM作用: 负责将字节码翻译为机器码,管理运行时内存 JVM整体组成部分: 类加载系统(ClasLoader):负责将硬盘上的字节码文件加载到内存中 运行时数据区(RuntimeData Area):负责存储运行时各种数据 执行引擎(Ex…

C++ 检查一条线是否与圆接触或相交(Check if a line touches or intersects a circle)

给定一个圆的圆心坐标、半径 > 1 的圆心坐标以及一条直线的方程。任务是检查给定的直线是否与圆相交。有三种可能性: 1、线与圆相交。 2、线与圆相切。 3、线在圆外。 注意:直线的一般方程是 a*x b*y c 0,因此输入中只给出常数 a、b、…

23. Merge k Sorted Lists

目录 题目描述 方法一、k-1次两两合并 方法二、分治法合并 方法三、使用优先队列 题目描述 23. Merge k Sorted Lists 方法一、k-1次两两合并 选第一个链表作为结果链表,每次将后面未合并的链表合并到结果链表中,经过k-1次合并,即可得到…

Unity + HybirdCLR热更新 入门篇

官方文档 HybridCLR | HybridCLRhttps://hybridclr.doc.code-philosophy.com/docs/intro 什么是HybirdCLR? HybridCLR(原名 huatuo)是一个专为 Unity 项目设计的C#热更新解决方案,它通过扩展 IL2CPP 运行时,使其支持动态加载和…

ElasticSearch迁移至openGauss

Elasticsearch 作为一种高效的全文搜索引擎,广泛应用于实时搜索、日志分析等场景。而 openGauss,作为一款企业级关系型数据库,强调事务处理与数据一致性。那么,当这两者的应用场景和技术架构发生交集时,如何实现它们之…

【C语言极简自学笔记】项目开发——扫雷游戏

一、项目概述 1.项目背景 扫雷是一款经典的益智游戏,由于它简单而富有挑战性的玩法深受人们喜爱。在 C 语言学习过程中,开发扫雷游戏是一个非常合适的实践项目,它能够综合运用 C 语言的多种基础知识,如数组、函数、循环、条件判…

Maven概述,搭建,使用

一.Maven概述 Maven是Apache软件基金会的一个开源项目,是一个有优秀的项目构建(创建)工具,它用来帮助开发者管理项目中的jar,以及jar之间的依赖关系,完成项目的编译,测试,打包和发布等工作. 我在当前学习阶段遇到过的jar文件: MySQL官方提供的JDBC驱动文件,通常命名为mysql-…

Unity 环境搭建

Unity是一款游戏引擎,可用于开发各种类型的游戏和交互式应用程序。它由Unity Technologies开发,并在多个平台上运行,包括Windows、macOS、Linux、iOS、Android和WebGL。Unity也支持虚拟现实(VR)和增强现实(AR)技术,允许用户构建逼…

【入门】【练9.3】 加四密码

| 时间限制:C/C 1000MS,其他语言 2000MS 内存限制:C/C 64MB,其他语言 128MB 难度:中等 分数:100 OI排行榜得分:12(0.1*分数2*难度) 出题人:root | 描述 要将 China…

使用 SASS 与 CSS Grid 实现鼠标悬停动态布局变换效果

最终效果概述 页面为 3x3 的彩色格子网格;当鼠标悬停任意格子,所在的行和列被放大;使用纯 CSS 实现,无需 JavaScript;利用 SASS 的模块能力大幅减少冗余代码。 HTML 结构 我们使用非常基础的结构,9 个 .i…

Spring如何实现组件扫描与@Component注解原理

Spring如何实现组件扫描与Component注解原理 注解配置与包扫描的实现机制一、概述:什么是注解配置与包扫描?二、处理流程概览三、注解定义ComponentScope 四、核心代码结构1. ClassPathScanningCandidateComponentProvider2. ClassPathBeanDefinitionSca…

达梦数据库 Windows 系统安装教程

🧑 博主简介:CSDN博客专家、CSDN平台优质创作者,高级开发工程师,数学专业,10年以上C/C, C#, Java等多种编程语言开发经验,拥有高级工程师证书;擅长C/C、C#等开发语言,熟悉Java常用开…

【Java EE初阶】计算机是如何⼯作的

计算机是如何⼯作的 计算机发展史冯诺依曼体系(Von Neumann Architecture)CPU指令(Instruction)CPU 是如何执行指令的(重点) 操作系统(Operating System)进程(process) 进程 PCB 中的…