Spring Boot中幂等性的应用

news/2024/12/26 3:39:51 标签: spring boot, 后端, java

Spring Boot 中,幂等性是实现分布式系统设计和接口调用的一个重要概念,尤其在高并发、分布式环境下,确保接口重复调用不会引发系统数据异常至关重要。

幂等性概念

幂等性(Idempotence)是指一次请求和重复多次请求对系统的影响完全相同。在接口调用中,如果一个接口满足幂等性,那么无论调用多少次,最终结果是一样的。

场景分析

  1. 支付系统
    防止重复支付。例如用户多次点击支付按钮,导致重复扣款。
  2. 订单创建
    防止用户重复下单,产生多个相同订单。
  3. 短信发送
    防止重复发送短信,避免浪费资源。
  4. 库存扣减
    防止并发扣减库存,导致库存不足或超卖。
  5. 分布式任务处理
    防止任务重复执行,保证最终一致性。

如何实现幂等性

在 Spring Boot 中,常用以下几种方法实现幂等性:

1.基于数据库唯一约束

原理:
利用数据库的唯一约束机制,确保同一请求只能操作一次。

实现:

  • 在数据库表中增加一个唯一字段(如订单号、请求 ID)。
  • 插入数据时,利用唯一约束防止重复写入。

代码示例:

java">@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 已使用,直接返回提示。

代码示例:

java">@RestController
@RequestMapping("/api/order")
public class OrderController {

    @Autowired
    private 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。
  • 若存在,直接返回处理结果。

代码示例:

java">@Service
public class OrderService {

    @Autowired
    private OrderRepository orderRepository;
    
    public String createOrder(String requestId, Order order) {
        // 校验幂等字段
        if (orderRepository.existsByRequestId(requestId)) {
            return "订单已创建,请勿重复提交";
        }
    
        // 保存订单
        order.setRequestId(requestId);
        orderRepository.save(order);
        return "订单创建成功";
    }

}

4.基于分布式锁

原理:

  • 利用分布式锁(如 Redis 的 SETNX)对关键资源加锁,确保同一时刻只有一个请求处理。

实现步骤:

  1. 请求时加锁,锁的唯一标识为幂等字段(如订单号)。
  2. 若加锁成功,执行业务逻辑。
  3. 业务执行完成后释放锁。

代码示例:

java">@Service
public class SmsService {

    @Autowired
    private 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.基于状态校验

原理:

  • 根据业务状态判断请求是否重复。
  • 常用于支付、库存等有明确状态的场景。

实现步骤:

  • 增加状态字段(如订单状态、支付状态)。
  • 请求前校验状态是否已完成。

代码示例:

java">@Service
public class PaymentService {

    @Autowired
    private 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 分布式锁:高并发场景,提升性能。
  • 幂等字段校验:需要记录唯一请求的场景。

幂等性设计不仅是接口安全的保障,更是系统稳定性的核心体现。


http://www.niftyadmin.cn/n/5799743.html

相关文章

Yolo11改进策略:Head改进|DynamicHead,利用注意力机制统一目标检测头部|即插即用

摘要 论文介绍 本文介绍了一种名为DynamicHead的模块,该模块旨在通过注意力机制统一目标检测头部,以提升目标检测的性能。论文详细阐述了DynamicHead的工作原理,并通过实验证明了其在COCO基准测试上的有效性和效率。 创新点 DynamicHead模块的创新之处在于它首次尝试在一…

YoloDotNet 识别图像中特定关键点的位置

文章目录 1、初始化 Yolo 对象2、加载图像与检测关键点3、处理检测结果4、自定义关键点绘制和处理5、注意事项1、初始化 Yolo 对象 设置 YoloOptions,包括模型路径、模型类型(如果有专门的关键点检测模型类型则指定)、GPU 使用相关参数等。例如: var yoloOptions = new Yo…

AI查重技术与传统查重技术的对比分析

引言 在学术界,论文查重是一个重要的环节,它不仅关系到学术诚信,也是保护知识产权的重要手段。随着人工智能技术的发展,AI查重技术逐渐成为主流,与传统查重技术相比,AI查重技术展现出了明显的优势。本文将…

批量多线程给TXT文档插入相关腾讯AI【高质量无水印无版权】原创图片

给蜘蛛访问的网站文章插入相关图片,可以带来以下好处: ‌1、提升用户体验‌:图片能够直观地展示文章内容,帮助用户更好地理解和消化信息。对于阅读者来说,图文并茂的内容往往更具吸引力,也能提高他们的阅读…

tomcat temp临时文件不清空,占用硬盘,jdk字体内存泄漏

JSP老旧项目迁移过来的代码,生成海报,会读取图片,读取字体文件,绘制图片,会生成大量临时文件,内存泄漏。 方案一,服务器定时删除temp临时文件夹 方案二,图片、字体改用静态类读取文件…

【深度学习实战:kaggle自然场景的图像分类-----使用keras框架实现vgg16的迁移学习】

项目简介 本次数据集来自kaggle,该数据集包括自然场景的图像。模型应该预测每个图像的正确标签。 您的目标是实现分类问题的高精度。 数据集 train.csv - 训练集 test.csv - 测试集 SceneImages - 图像文件夹 训练集的数据格式如下: image_namelabe…

Springboot基于Web的高校志愿者服务管理系统81559

Springboot基于Web的高校志愿者服务管理系统81559 本系统(程序**源码数据库调试部署开发环境)带论文文档1****万字以上,文末可获取,系统界面在最后面。** 系统程序文件列表 项目功能: 志愿者,团队,招募机构,团队信息…

TLDR:终端命令的简洁百科全书

TLDR,全称 “Too Long, Don’t Read”,是一款特别实用的终端命令百科全书工具。通过 TLDR,您可以快速查找到常用命令的使用方法,避免繁琐冗长的官方文档,让日常工作更加高效。 为什么选择 TLDR? 简单易用&…