redis+token+分布式锁确保接口的幂等性

目录

1.幂等性是什么?

2.如何实现幂等性呢?

1.新增管理员,出弹窗的同时,请求后台。

2.后端根据雪花算法生成唯一标识key,以雪花数为key存到redis。并返回key给前端。

3.前端保存后端传过来的key。

4.前端输入完成信息,点击【保存】,携带key请求后端。

5.请求到达后端,验证key,根据key去redis里查,如果得不到值,说明已处理过。否则尝试获取redisson锁,然后处理业务,并删掉redis里的值。


1.幂等性是什么?

新增和修改功能的时候,常常需要用到幂等性。

所谓的幂等性就是,即使不小心多按了几次,仍然只执行一次。常用在下单、增量修改、插入数据的时候。

效果:

在同一时间狂点鼠标"新增",或者jmter压测并发多线程访问这个接口,也执行一次新增。

2.如何实现幂等性呢?

本次案例采用,token+redis+分布式锁:

流程如下所示:

1.新增管理员,出弹窗的同时,请求后台。

复制代码
//获取唯一标识
    beforeAdd() {
      setTimeout(() => {
        this.dialogAdd = true;
      }, 500);
      //请求后台拿唯一标识
      (this.imageUrl = ""),
        this.$axios.get("/api/pc-zdy-sys/admin/preAddAdmin").then((res) => {
          if (res.data.code == 200) {
            this.allRoleList = res.data.data.allRoleList; //系统里所有的角色
            this.key = res.data.data.key; //唯一标识key
          }
        });
    },

2.后端根据雪花算法生成唯一标识key,以雪花数为key存到redis。并返回key给前端。

复制代码
 public String preAddAdmin() {
        //雪花id 为key存到redis 值可以无意义
        Long snowflakeNextId = IdUtil.getSnowflakeNextId();
        String key = String.valueOf(snowflakeNextId);
        redisTemplate.opsForValue().set(key,"唯一标识");
        //返回雪花id
        return key;
    }

3.前端保存后端传过来的key。

复制代码
data() {
    return {
      key: "", //唯一标识key
    };
  },

4.前端输入完成信息,点击【保存】,携带key请求后端。

复制代码
confirmAdd() {
      
      //key带到后台去,请求接口确认新增
      this.AddAdmin.url = this.imageUrl;
      this.AddAdmin.key = this.key;
      if(this.isAnyFieldEmpty){
        this.$message({
              message: "不能为空",
              type: "danger",
            });
      
        return;
      }
      this.$axios
        .post("/api/pc-zdy-sys/admin", this.AddAdmin)
        .then((res) => {
          if (res.data.code == 200) {
            this.$message({
              message: "恭喜你,新增成功",
              type: "success",
            });
            this.dialogAdd = false;
            this.queryAdmin()
          }
        })
        .catch((error) => {
          this.$message({
            message: "新增失败",
            type: "danger",
          });
        });
    },

5.请求到达后端,验证key,根据key去redis里查,如果得不到值,说明已处理过。否则尝试获取redisson锁,然后处理业务,并删掉redis里的值。

复制代码
public void addAdmin(UserDTO userDTO) {
        //根据key找是否有token
        String key = userDTO.getKey();
         if(StringUtils.isBlank(key)||ObjectUtil.isEmpty(redisTemplate.opsForValue().get(key))){
            //没有key或根据key找不到token直接抛异常
            throw new RuntimeException("新增失败");
        }
        //拿锁去处理
        RLock lock = redissonClient.getLock(key);

        boolean b = lock.tryLock();

        //如果拿锁失败
        if(!b){
            throw new RuntimeException("新增失败");
        }
        lock.lock();
        try {
            //admin加到用户表
            User user = new User();
            BeanUtils.copyProperties(userDTO,user);
            user.setStatus(1);
            userMapper.insert(user);
            //将userDTO里角色list加到角色-用户 中间表去
            //需要用户id 角色id集合
            userRoleMapper.addRoleListToUserRole(user.getId(),userDTO.getRoleList());
            //删掉缓存
            redisTemplate.delete(key);
        
        } catch (Exception e){
            e.printStackTrace();
        }finally {
            lock.unlock();
        }
    }
相关推荐
gwcgwcjava4 分钟前
[时序数据库-iotdb]时序数据库iotdb的安装部署
数据库·时序数据库·iotdb
remCoding11 分钟前
Java全栈面试实录:从电商场景到AIGC的深度技术考察
spring boot·redis·spring cloud·ai·kafka·aigc·java面试
SHUIPING_YANG18 分钟前
根据用户id自动切换表查询
java·服务器·数据库
爱吃烤鸡翅的酸菜鱼30 分钟前
IDEA高效开发:Database Navigator插件安装与核心使用指南
java·开发语言·数据库·编辑器·intellij-idea·database
超奇电子35 分钟前
阿里云OSS预签名URL上传与临时凭证上传的技术对比分析
数据库·阿里云·云计算
神仙别闹1 小时前
基于C#+SQL Server实现(Web)学生选课管理系统
前端·数据库·c#
m0_653031361 小时前
PostgreSQL技术大讲堂 - 第97讲:PG数据库编码和区域(locale)答疑解惑
数据库·postgresql
会编程的林俊杰1 小时前
MySQL中的锁有哪些
数据库·mysql
cts6181 小时前
Milvus分布式数据库工作职责
数据库·分布式·milvus
周胡杰1 小时前
鸿蒙加载预置数据库-关系型数据库-如何读取本地/预制数据库
数据库·华为·harmonyos·鸿蒙