• 分布式常见问题丨高并发时重复提交,基于Redis的幂等性解决方案来啦


    原创作者:千锋威尔逊

    一. 幂等性

    所谓的幂等性,是分布式环境下的一个常见问题,一般是指我们在进行多次操作时,所得到的结果是一样的,即多次运算结果是一致的。

    也就是说,用户对于同一操作,无论是发起一次请求还是多次请求,最终的执行结果是一致的,不会因为多次点击而产生副作用。

    二. 常见幂等性操作

    在我们进行代码实现时,常见的请求有如下几种,他们的幂等性如下:

    • select查询天然幂等;

    • delete删除也是幂等,删除同一个数据多次其效果一样;

    • update直接更新某个值时,幂等;

    • update更新累加操作的的结果,非幂等;

    • insert操作会每次都新增一条,非幂等;

    三. 什么情况下会产生重复提交(非幂等性)

    以下几种情况会导致非幂等性的结果出现:

    • 连续点击提交两次按钮;

    • 点击刷新按钮;

    • 使用浏览器后退按钮重复之前的操作,导致重复提交表单;

    • 使用浏览器历史记录重复提交表单;

    • 浏览器重复地HTTP请求等。

    四. 解决方案

    我们在开发时,解决幂等性的常见方式有以下几种:

    1.前端js提交禁止按钮可以用一些js组件

    2.使用Post/Redirect/Get模式

    在提交后执行页面重定向,这就是所谓的Post-Redirect-Get (PRG)模式。简言之,当用户提交了表单后,你去执行一个客户端的重定向,转到提交成功信息页面。

    这能避免用户按F5导致的重复提交,而其也不会出现浏览器表单重复提交的警告,也能消除按浏览器前进和后退按导致的同样问题。

    3.借助数据库操作

    insert唯一索引,保证插入的数据只有一条。另外也可以基于悲观锁或者乐观锁,先查询后判断,首先通过查询数据库是否存在数据,如果存在证明已经请求过了,直接拒绝该请求;如果没有存在,就证明是第一次进来,直接放行。

    4.session机制(后台服务端)

    在服务器端,生成一个唯一的标识符,将它存入session,同时将它写入表单的隐藏字段中,然后将表单页面发给浏览器,用户录入信息后点击提交。

    另外在服务器端,获取表单中隐藏字段的值,与session中的唯一标识符比较,如果相等说明是首次提交,就处理本次请求,然后将session中的唯一标识符移除,如果不相等即重复提交。

    5.Redis token机制

    每次接口请求前先获取一个token,然后再下次请求的时候在请求的header体中加上这个token,后台进行验证。如果验证通过删除token,下次请求再次判断token是否相等,如果不相等即重复提交。

    五. Redis token的代码实现

    接下来我就把Redis token方式的实现代码列出,如下所示:

    1. package com.qfjy.project.meeting.util;
    2. import lombok.extern.slf4j.Slf4j;
    3. import org.springframework.beans.factory.annotation.Autowired;
    4. import org.springframework.data.redis.core.RedisTemplate;
    5. import org.springframework.stereotype.Component;
    6. import java.util.UUID;
    7. import java.util.concurrent.TimeUnit;
    8. /**
    9.  * @ClassName RedisRepeatUtil
    10.  * @Description TODO  Redis解决重复提交
    11.  * @Author guoweixin
    12.  * @Date 2022/4/19
    13.  * @Version 1.0
    14.  */
    15. @Slf4j
    16. @Component
    17. public class RedisRepeatUtil {
    18.     /**Redis中间件*/
    19.     @Autowired
    20.     private RedisTemplate<String,Object> redisTemplate;
    21.     /**
    22.      * 会议发布页面KEY
    23.      */
    24.     public static String MEETING_MEMETING_PUB_ADD_KEY="meeting:meetingPub:pageToken:";
    25.     /**
    26.      * 会议抢单页面(进行页面)KEY
    27.      */
    28.     public static String MEETING_MEETING_GRAB_ADD_KEY="meeting:meetingGrab:add:pageToken:";
    29.     /**
    30.      * TODO 进入页面 生成token
    31.      * 1、命令是根据进入页面的名称+用户ID
    32.      * 2、过期时间是30分钟(为了避免产生无效的内存数据浪费)
    33.      * @param key  redis key
    34.      * @return
    35.      */
    36.     public String generToken(String key){
    37.         String uuid= UUID.randomUUID().toString();
    38.         log.info("uuid:"+uuid);
    39.         //为期设置过期时
    40.         redisTemplate.opsForValue().set(key, uuid);
    41.         redisTemplate.expire(key,30TimeUnit.MINUTES);
    42.         return uuid;
    43.     }
    44.     /**
    45.      * TODO(解决重复提交)
    46.      * 前端 token和后端redis token进行比较判断
    47.      * @param tokenUUID
    48.      * @return
    49.      */
    50.     public boolean  compareToken(String key,String tokenUUID){
    51.         //删除key
    52.         boolean flag=tokenUUID.equals((String) redisTemplate.opsForValue().get(key));
    53.         redisTemplate.delete(key);
    54.         return flag;
    55.     }
    56. }

    以上代码用来生成保证幂等性的token,我们会发现代码并不复杂。现在你知道怎么保证幂等性了吗?评论区说说你的看法呗。

    要是想学习更多技术点,可以加下方小姐姐微信领取最新教程、源码、笔记

     

  • 相关阅读:
    关于scanf和printf的格式控制修饰符
    2021年电工杯数学建模B题光伏建筑一体化板块指数发展趋势分析及预测求解全过程论文及程序
    1004 成绩排名
    C语言的语句与程序的基本结构
    VUE基础知识三:数组常用的操作函数
    Spring Mvc 拦截器详解
    户外景区亲子儿童剧本杀小程序小程序开发搭建
    Mybatis-Plus同时使用逻辑删除和唯一索引的问题及解决办法
    EPSS 解读:与 CVSS 相比,孰美?
    【雷达】基于TI毫米波雷达IWR6843ISK实现室内人员检测附matlab代码
  • 原文地址:https://blog.csdn.net/finally_vince/article/details/125445293