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();
        }
    }
相关推荐
陌上丨7 小时前
Redis的Key和Value的设计原则有哪些?
数据库·redis·缓存
AI_56787 小时前
AWS EC2新手入门:6步带你从零启动实例
大数据·数据库·人工智能·机器学习·aws
ccecw7 小时前
Mysql ONLY_FULL_GROUP_BY模式详解、group by非查询字段报错
数据库·mysql
JH30737 小时前
达梦数据库与MySQL的核心差异解析:从特性到实践
数据库·mysql
数据知道8 小时前
PostgreSQL 核心原理:如何利用多核 CPU 加速大数据量扫描(并行查询)
数据库·postgresql
麦聪聊数据9 小时前
Web 原生架构如何重塑企业级数据库协作流?
数据库·sql·低代码·架构
未来之窗软件服务9 小时前
数据库优化提速(四)新加坡房产系统开发数据库表结构—仙盟创梦IDE
数据库·数据库优化·计算机软考
时艰.10 小时前
Java 并发编程 — 并发容器 + CPU 缓存 + Disruptor
java·开发语言·缓存
Goat恶霸詹姆斯10 小时前
mysql常用语句
数据库·mysql·oracle
大模型玩家七七11 小时前
梯度累积真的省显存吗?它换走的是什么成本
java·javascript·数据库·人工智能·深度学习