Spring Boot中幂等性的应用
在 Spring Boot 中,幂等性是实现分布式系统设计和接口调用的一个重要概念,尤其在高并发、分布式环境下,确保接口重复调用不会引发系统数据异常至关重要。
幂等性概念
幂等性(Idempotence)是指一次请求和重复多次请求对系统的影响完全相同。在接口调用中,如果一个接口满足幂等性,那么无论调用多少次,最终结果是一样的。
场景分析
- 支付系统
防止重复支付。例如用户多次点击支付按钮,导致重复扣款。 - 订单创建
防止用户重复下单,产生多个相同订单。 - 短信发送
防止重复发送短信,避免浪费资源。 - 库存扣减
防止并发扣减库存,导致库存不足或超卖。 - 分布式任务处理
防止任务重复执行,保证最终一致性。
如何实现幂等性
在 Spring Boot 中,常用以下几种方法实现幂等性:
1.基于数据库唯一约束
原理:
利用数据库的唯一约束机制,确保同一请求只能操作一次。
实现:
- 在数据库表中增加一个唯一字段(如订单号、请求 ID)。
- 插入数据时,利用唯一约束防止重复写入。
代码示例:
@Entity
@Table(name = "orders", uniqueConstraints = {@UniqueConstraint(columnNames = "orderId")})
public class Order {@Id@GeneratedValue(strategy = GenerationType.IDENTITY)private Long id;@Column(nullable = false)private String orderId; // 唯一订单号@Column(nullable = false)private BigDecimal amount;}
当重复提交时,数据库会抛出 DuplicateKeyException,可以捕获并返回提示。
2.基于唯一 Token 实现
原理:
- 每次请求都需要携带唯一的 token,服务器校验 token 是否已使用。
- 若已使用,则拒绝请求。
实现步骤:
1.客户端向服务器申请唯一 token(如 UUID)。
2.在请求时携带 token。
3.服务端验证 token:
- 若 token 未使用,处理业务并标记 token 为已使用。
- 若 token 已使用,直接返回提示。
代码示例:
@RestController
@RequestMapping("/api/order")
public class OrderController {@Autowiredprivate StringRedisTemplate redisTemplate;@PostMapping("/create")public String createOrder(@RequestParam String token) {// 校验 token 是否已存在Boolean isTokenExists = redisTemplate.opsForValue().setIfAbsent(token, "1", 10, TimeUnit.MINUTES);if (Boolean.FALSE.equals(isTokenExists)) {return "重复请求,请勿再次提交";}// 执行业务逻辑// ...return "订单创建成功";}}
优点:
- 无需修改数据库结构。
- 使用 Redis 提高性能,适用于高并发场景。
3.基于幂等字段校验
原理:
- 接口请求体中包含幂等字段(如订单号、请求 ID)。
- 服务端通过幂等字段判断请求是否已处理。
实现步骤:
- 在业务表中增加 requestId 字段,标记唯一请求。
- 每次请求前查询是否存在相同的 requestId。
- 若存在,直接返回处理结果。
代码示例:
@Service
public class OrderService {@Autowiredprivate OrderRepository orderRepository;public String createOrder(String requestId, Order order) {// 校验幂等字段if (orderRepository.existsByRequestId(requestId)) {return "订单已创建,请勿重复提交";}// 保存订单order.setRequestId(requestId);orderRepository.save(order);return "订单创建成功";}}
4.基于分布式锁
原理:
- 利用分布式锁(如 Redis 的 SETNX)对关键资源加锁,确保同一时刻只有一个请求处理。
实现步骤:
- 请求时加锁,锁的唯一标识为幂等字段(如订单号)。
- 若加锁成功,执行业务逻辑。
- 业务执行完成后释放锁。
代码示例:
@Service
public class SmsService {@Autowiredprivate StringRedisTemplate redisTemplate;public String sendSms(String phoneNumber) {String lockKey = "sms:lock:" + phoneNumber;// 加锁Boolean isLockAcquired = redisTemplate.opsForValue().setIfAbsent(lockKey, "1", 2, TimeUnit.MINUTES);if (Boolean.FALSE.equals(isLockAcquired)) {return "短信发送过于频繁,请稍后再试";}try {// 执行业务逻辑// ...return "短信发送成功";} finally {// 释放锁redisTemplate.delete(lockKey);}}}
5.基于状态校验
原理:
- 根据业务状态判断请求是否重复。
- 常用于支付、库存等有明确状态的场景。
实现步骤:
- 增加状态字段(如订单状态、支付状态)。
- 请求前校验状态是否已完成。
代码示例:
@Service
public class PaymentService {@Autowiredprivate OrderRepository orderRepository;public String payOrder(Long orderId) {Order order = orderRepository.findById(orderId).orElseThrow(() -> new RuntimeException("订单不存在"));// 校验状态if (order.getStatus().equals("PAID")) {return "订单已支付,请勿重复操作";}// 修改订单状态order.setStatus("PAID");orderRepository.save(order);return "支付成功";}}
幂等性设计注意事项
1.选择合适的幂等方案
- 数据库唯一约束适合低并发场景。
- Redis 分布式锁适合高并发场景。
- 幂等字段校验适合需要记录请求 ID 的场景。
2.幂等字段的设计
- 幂等字段应具有唯一性,如订单号、请求 ID。
- 客户端生成或服务端分配均可。
3.幂等性与事务
- 确保幂等校验与业务逻辑在同一事务中执行,避免校验通过但业务未执行完成的情况。
4.性能优化
- 使用缓存(如 Redis)提高幂等校验性能,减少数据库压力。
总结
Spring Boot 中的幂等性实现,是确保接口安全性和数据一致性的关键。根据业务场景的不同,选择合适的幂等方案至关重要:
- 数据库唯一约束:简单场景,直接使用。
- Redis 分布式锁:高并发场景,提升性能。
- 幂等字段校验:需要记录唯一请求的场景。
幂等性设计不仅是接口安全的保障,更是系统稳定性的核心体现。
相关文章:
Spring Boot中幂等性的应用
在 Spring Boot 中,幂等性是实现分布式系统设计和接口调用的一个重要概念,尤其在高并发、分布式环境下,确保接口重复调用不会引发系统数据异常至关重要。 幂等性概念 幂等性(Idempotence)是指一次请求和重复多次请求…...
【机器学习】分类
文章目录 1. 能否用回归解决分类问题2. 生成模型(概率生成)3. 判别模型(逻辑回归)4. 多分类问题 1. 能否用回归解决分类问题 二元分类 数据分布不规律,回归函数会尽量减少误差,导致不合理的偏移离分界较远…...

5.若依的角色权限控制
RBAC 基于角色的访问控制,通过角色来分配和管理用户的菜单权限。 修改课程管理的菜单到主类目下 新建角色并分配菜单 新建用户并分配角色 添加一个根菜单,父级为主类目...

Lumos学习王佩丰Excel第二十三讲:饼图美化与PPT图表
一、双坐标柱形图的补充知识 1、主次坐标设置 2、主次坐标柱形避让(通过增加两个系列,挤压使得两个柱形挨在一起) 增加两个系列 将一个系列设置成主坐标轴,另一个设成次坐标轴 调整系列位置 二、饼图美化 1、饼图美化常见设置 …...

安装winserver2008R2虚拟机步骤
一、服务器系统介绍 1.1什么是服务器? 服务器英文名称为“Server”,指的是网络环境下为客户机(Client)提供某种服务的专用计算机,服务器安装有网络操作系统(如Windows 2000 Server、Linux、Unix等)和各种服务器应用系统软件(如Web服务、电子…...
ACPI PM Timer
ACPI PM Timer 概述: ACPI PM Timer是一个非常简单的计时器,它以 3.579545 MHz 运行,在计数器溢出时生成系统控制中断(SCI)。它精度较低,建议使用其他定时器,如HPET或APIC定时器。 检测ACPI P…...
Linux 和设备树
“开放固件设备树”,简称 Devicetree (DT),是一种用于描述硬件的数据结构和语言。更具体地说,它是操作系统可读取的硬件描述,因此操作系统无需对机器的详细信息进行硬编码。 从结构上看,DT 是一棵树,或具有…...
Qt仿音乐播放器:QFileDialog添加本地文件
一、套路 QFileDialog fileDialog(this);// 创建对话框,并设置父元素;fileDialog.setWindowTitle("添加本地下载的音乐");//设置窗口标题//设置文件对话框的默认打开路径 QString projectPathQDir::currentPath();//获取当前目录 QDir dir(pr…...
Odoo 引用字段 fields.Reference:动态关系的选择器
在 Odoo 模型开发中,关系型字段是构建复杂应用的基础。 然而,传统的 m2o、o2m 和 m2m 字段需要在模型定义时就明确指定关系的目标模型,这在某些场景下会显得不够灵活。 为了解决这个问题,Odoo 提供了 fields.Reference 引用字段&a…...

Android笔试面试题AI答之Android基础(6)
Android入门请看《Android应用开发项目式教程》 文章目录 1.Android Studio版本与Gradle版本有什么关联?**1. Gradle 的作用****2. Android Studio 与 Gradle 的关系****3. 版本对应关系****4. 如何查看和修改版本****查看当前版本****修改版本** **5. 版本不兼容的…...

C# 中的记录类型简介 【代码之美系列】
🎀🎀🎀代码之美系列目录🎀🎀🎀 一、C# 命名规则规范 二、C# 代码约定规范 三、C# 参数类型约束 四、浅析 B/S 应用程序体系结构原则 五、浅析 C# Async 和 Await 六、浅析 ASP.NET Core SignalR 双工通信 …...

利用Java爬虫速卖通按关键字搜索AliExpress商品
在这个信息爆炸的时代,数据的价值日益凸显。对于电商领域的从业者来说,能够快速获取商品信息成为了一项重要的技能。速卖通(AliExpress)作为全球领先的跨境电商平台,拥有海量的商品数据。本文将介绍如何使用Java语言编…...
gitlab runner 实现 微信小程序自动化部署
微信小程序多人开发的情况下,开发人员都只能在本机上发布体验版,且需要到小程序管理后台自行切换到自己发布的版本,会出现体验版本覆盖的问题。给开发测试带来问题。 miniprogram-ci 的发布,使得开发人员可以通过命令行上传小程序…...
Playwright爬虫xpath获取技巧
示例一 <button class"MuiButtonBase-root MuiButton-root MuiLoadingButton-root MuiButton-contained MuiButton-containedPrimary MuiButton-sizeLarge MuiButton-containedSizeLarge MuiButton-colorPrimary MuiButton-fullWidth MuiButton-root MuiLoadingButton…...

总结TCP/IP四层模型
总结TCP/IP四层模型 阅读目录(Content) 一、TCP/IP参考模型概述 1.1、TCP/IP参考模型的层次结构二、TCP/IP四层功能概述 2.1、主机到网络层 2.2、网络互连层 2.3、传输层 2.3、应用层 三、TCP/IP报文格式 3.1、IP报文格式3.2、TCP数据段格式3.3、UDP数据段格式3.4、套…...
netcat和nmap的区别
Netcat 和 Nmap 是两种广泛使用的网络工具,但它们的功能和使用场景有所不同。下面是这两种工具的对比: Netcat(nc) 用途和功能: 网络连接: Netcat 是一个功能强大的网络工具,用于创建 TCP 或 UDP 连接。可以用来进行网…...
MinIO服务器文件复制(Windows环境Linux环境)
一、下载 Windows环境:https://dl.min.io/server/minio/release/windows-amd64/minio.exe Linux环境: > curl https://dl.min.io/client/mc/release/linux-amd64/mc \ --create-dirs \ -o $HOME/minio/mc > chmod x $HOME/minio/mc > expo…...

【机器学习】【朴素贝叶斯分类器】从理论到实践:朴素贝叶斯分类器在垃圾短信过滤中的应用
🌟 关于我 🌟 大家好呀!👋 我是一名大三在读学生,目前对人工智能领域充满了浓厚的兴趣,尤其是机器学习、深度学习和自然语言处理这些酷炫的技术!🤖💻 平时我喜欢动手做实…...
无监督学习算法
K-均值聚类(K-means clustering)是一种常用的无监督学习算法,用于将数据集划分成 K 个不同的组或簇。该算法主要通过计算数据点之间的欧几里得距离来确定数据点之间的相似性,并根据相似性将数据点分配到不同的簇中,使得…...

【Compose multiplatform教程17】【组件】BoxWithConstraints组件
查看全部组件 https://blog.csdn.net/b275518834/article/details/144751353 BoxWithConstraints 功能说明:它是 Jetpack Compose 中的关键布局组件,能够精准捕捉自身所在容器的尺寸约束信息,通过获取最大宽度和最大高度这两个关键属性&…...

【kafka】Golang实现分布式Masscan任务调度系统
要求: 输出两个程序,一个命令行程序(命令行参数用flag)和一个服务端程序。 命令行程序支持通过命令行参数配置下发IP或IP段、端口、扫描带宽,然后将消息推送到kafka里面。 服务端程序: 从kafka消费者接收…...

shell脚本--常见案例
1、自动备份文件或目录 2、批量重命名文件 3、查找并删除指定名称的文件: 4、批量删除文件 5、查找并替换文件内容 6、批量创建文件 7、创建文件夹并移动文件 8、在文件夹中查找文件...

Debian系统简介
目录 Debian系统介绍 Debian版本介绍 Debian软件源介绍 软件包管理工具dpkg dpkg核心指令详解 安装软件包 卸载软件包 查询软件包状态 验证软件包完整性 手动处理依赖关系 dpkg vs apt Debian系统介绍 Debian 和 Ubuntu 都是基于 Debian内核 的 Linux 发行版ÿ…...

(二)TensorRT-LLM | 模型导出(v0.20.0rc3)
0. 概述 上一节 对安装和使用有个基本介绍。根据这个 issue 的描述,后续 TensorRT-LLM 团队可能更专注于更新和维护 pytorch backend。但 tensorrt backend 作为先前一直开发的工作,其中包含了大量可以学习的地方。本文主要看看它导出模型的部分&#x…...
C# SqlSugar:依赖注入与仓储模式实践
C# SqlSugar:依赖注入与仓储模式实践 在 C# 的应用开发中,数据库操作是必不可少的环节。为了让数据访问层更加简洁、高效且易于维护,许多开发者会选择成熟的 ORM(对象关系映射)框架,SqlSugar 就是其中备受…...

SpringCloudGateway 自定义局部过滤器
场景: 将所有请求转化为同一路径请求(方便穿网配置)在请求头内标识原来路径,然后在将请求分发给不同服务 AllToOneGatewayFilterFactory import lombok.Getter; import lombok.Setter; import lombok.extern.slf4j.Slf4j; impor…...
2023赣州旅游投资集团
单选题 1.“不登高山,不知天之高也;不临深溪,不知地之厚也。”这句话说明_____。 A、人的意识具有创造性 B、人的认识是独立于实践之外的 C、实践在认识过程中具有决定作用 D、人的一切知识都是从直接经验中获得的 参考答案: C 本题解…...

基于TurtleBot3在Gazebo地图实现机器人远程控制
1. TurtleBot3环境配置 # 下载TurtleBot3核心包 mkdir -p ~/catkin_ws/src cd ~/catkin_ws/src git clone -b noetic-devel https://github.com/ROBOTIS-GIT/turtlebot3.git git clone -b noetic https://github.com/ROBOTIS-GIT/turtlebot3_msgs.git git clone -b noetic-dev…...

嵌入式学习笔记DAY33(网络编程——TCP)
一、网络架构 C/S (client/server 客户端/服务器):由客户端和服务器端两个部分组成。客户端通常是用户使用的应用程序,负责提供用户界面和交互逻辑 ,接收用户输入,向服务器发送请求,并展示服务…...

push [特殊字符] present
push 🆚 present 前言present和dismiss特点代码演示 push和pop特点代码演示 前言 在 iOS 开发中,push 和 present 是两种不同的视图控制器切换方式,它们有着显著的区别。 present和dismiss 特点 在当前控制器上方新建视图层级需要手动调用…...