zoukankan      html  css  js  c++  java
  • 接口防重复提交

    ps:以前经常会处理此类问题,但一直没有闲暇时间记录,今天就把这个东西记录一下。
    此方法只是单机版的,分布式的需要考虑例如redis的setnx锁,这个后续会出随笔

    1、提出问题

    业务中不可避免出现重复提交的问题,场景大概如下:

    ​ 用户请求开户,后端接口处于开户处理中,在这个过程中,用户再次请求开户,那么此时在未做对应处理的情况下,即使业务代码中去判断开户重复也是无用的,因为一般增删改操作处于事务当中,后一个请求不会读取到上一个请求未提交事务的数据(如果读取到了那就是脏读),所以我们得在业务代码执行之前进行相应的防重复提交处理。

    2、解决方案

    大概思路如下:

    ​ 1、用户第一次请求时,放置到Redis中一个标志位,然后执行业务代码。

    ​ 2、用户在第一次请求未结束时再次请求的情况下,该请求方法事先去看Redis中上一个标志位的key是否存在,如果还存在,那么则代表上一次请求还未处理结束,那么这个时候就不执行业务代码,直接返回用户 “重复提交” 的反馈。

    实现代码如下:

    1    public R examEnd(String uuid) throws Exception {
    2        boolean isProcessing = false;
    3        synchronized (YsExeamDataPushController.this) {
    4            /* 为空则代表还未执行过,那么则加入缓存 */
    5            if (Objects.isNull(redisService.getCacheObject("自定义的前缀" + uuid))) {
    6                /* 存入缓存,最多五分钟 */
    7                redisService.setCacheObject("自定义的前缀" + uuid, uuid,300L, TimeUnit.SECONDS);
    8            } else {
    9                isProcessing = true;
    10            }
    11        }
    12        /* 是否正在执行 */
    13       if (!isProcessing) {
    14            return R.checkUpdate(iDataPushService.handlerExamEnd(uuid));
    15        } else {
    16            return R.fail("UUID为:" + uuid + ",的考试答案正在处理中,请勿重复处理!");
    17        }
    18    }
    

    此处思路如下:

    ​ 1、len 2:首先定义一个变量isProcessing,此变量为true的情况下,说明上一次请求还未结束,为false的话说明是第一次请求

    ​ 2、len 5:然后从redis中获取相对应的标志位,如果不存在的情况下后序需要去执行相应的业务方法,那么则存入标志位到redis中

    ​ 3、len 13:根据isProcessing的状态去判断是否需要执行业务方法。

    ​ 4、len 3:注意这里为什么要去加入synchronized代码块,

    ​ 如果不加的话:如果同时大于或等于2个的请求到达第5行判断redis中是否存在标志位的情况下,那么则会造成这2个请求的判断结果都是第一次请求,那么这个防重复提交则失效了。

    ​ 如果加了的话:就算是再多的请求同时到达,那么在同一个时间下也只有一个请求能进入代码块内,我们保证了判断标志位+设置isProcessing的操作是原子性的,这样的话就避免了上述的情况。

    ​ 5、注意:该请求无论处理结果如何,都需要删除在redis中的标志位。

    3、其他

    记得让前端对提交按钮做防止重复点击的操作,例如点一次后就不能点了这种得。

    当然,处理防重复提交这并不是最好的方案,但优点于简单、直接,此方法试用绝大多数语言,核心方法就是使用redis做标志位。

    上述代码比较冗余,有兴趣的可以将其抽取到AOP当中,加一个注解,AOP切入这个注解,环绕通知(做判断标志位和存入标志位)+返回通知(删除标志位)。

    网上有很多其余的防重复提交的操作,有兴趣的可以去搜搜看。

  • 相关阅读:
    巴洛克式和哥特式的区别
    推荐阅读书籍,是时候再行动起来了。
    AtCoder ABC 159F Knapsack for All Segments
    AtCoder ABC 159E Dividing Chocolate
    AtCoder ABC 158F Removing Robots
    AtCoder ABC 158E Divisible Substring
    AtCoder ABC 157F Yakiniku Optimization Problem
    AtCoder ABC 157E Simple String Queries
    AtCoder ABC 157D Friend Suggestions
    AtCoder ABC 156F Modularness
  • 原文地址:https://www.cnblogs.com/daihang2366/p/14694770.html
Copyright © 2011-2022 走看看