返回

从 Spring Boot + Redis 聊一聊如何解决重复提交问题

后端

前言

在实际的开发项目中,一个对外暴露的接口往往会面临很多次请求,我们来解释一下什么叫重复提交。例如,用户点击一个按钮触发一个请求,但是由于网络原因,请求没有成功,用户又点击了一次按钮,这就造成了重复提交。

重复提交会导致数据不一致,甚至导致系统崩溃。那么,我们该如何解决重复提交问题呢?Spring Boot 和 Redis 联手出击,为我们提供了优雅的解决方案。

理解重复提交问题

重复提交问题是指同一个请求被多次提交。在实际开发中,重复提交问题可能由多种因素引起,包括:

  • 网络延迟:由于网络延迟,请求可能被发送多次。
  • 用户操作:用户可能多次点击按钮或刷新页面,导致重复提交。
  • 服务器故障:服务器故障可能导致请求被重复提交。

重复提交问题会导致多种后果,包括:

  • 数据不一致:重复提交问题可能导致数据不一致,例如,同一张订单被创建多次。
  • 系统崩溃:重复提交问题可能导致系统崩溃,例如,当系统收到大量重复请求时。

Spring Boot + Redis 解决重复提交问题

为了解决重复提交问题,Spring Boot 和 Redis 联手出击,为我们提供了两种解决方案:基于注解的解决方案和基于拦截器的解决方案。

基于注解的解决方案

Spring Boot 提供了 @Idempotent 注解,我们可以使用该注解来标记需要保证幂等性的方法。当使用 @Idempotent 注解标记的方法被调用时,Spring Boot 会自动检查该方法是否已经执行过。如果该方法已经执行过,Spring Boot 会返回一个 409 Conflict 状态码,表示该请求是重复提交的。

例如,我们可以使用 @Idempotent 注解标记一个创建订单的方法:

@PostMapping("/orders")
@Idempotent
public Order createOrder(@RequestBody Order order) {
    // 创建订单
    return orderService.createOrder(order);
}

基于拦截器的解决方案

Spring Boot 也提供了 RepeatSubmitInterceptor 拦截器,我们可以使用该拦截器来拦截重复提交的请求。当 RepeatSubmitInterceptor 拦截到重复提交的请求时,它会返回一个 409 Conflict 状态码,表示该请求是重复提交的。

例如,我们可以使用 RepeatSubmitInterceptor 拦截所有 POST 请求:

public class RepeatSubmitConfig {

    @Bean
    public RepeatSubmitInterceptor repeatSubmitInterceptor() {
        return new RepeatSubmitInterceptor();
    }

    @Bean
    public WebMvcConfigurer webMvcConfigurer(RepeatSubmitInterceptor repeatSubmitInterceptor) {
        return new WebMvcConfigurer() {
            @Override
            public void addInterceptors(InterceptorRegistry registry) {
                registry.addInterceptor(repeatSubmitInterceptor).addPathPatterns("/**");
            }
        };
    }
}

幂等性

幂等性是指一个操作无论执行多少次,产生的结果都是一样的。幂等性是解决重复提交问题的关键。如果一个操作是幂等的,那么即使它被执行多次,也不会产生任何问题。

在 Spring Boot 中,我们可以使用 @Idempotent 注解或 RepeatSubmitInterceptor 拦截器来保证操作的幂等性。

总结

重复提交问题是一个常见的