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();
        }
    }
相关推荐
特立独行的猫a15 小时前
PostgreSQL客户端工具介绍:从性能测试到跨平台管理
数据库·docker·postgresql·客户端·pgadmin4
微爱帮监所写信寄信15 小时前
微爱帮监狱写信寄信小程序:MySQL核心日志与备份恢复安全架构
数据库·mysql·小程序·邮局·监狱寄信·挂号信·邮政
isNotNullX16 小时前
数据迁移怎么做?有什么好用的数据库迁移工具推荐吗?
数据库·数字化·数据迁移·企业管理
云老大TG:@yunlaoda36016 小时前
华为云国际站代理商DAS的跨境合规适配的应用场景有哪些?
网络·数据库·华为云
38242782717 小时前
python3网络爬虫开发实战 第二版:绑定回调
开发语言·数据库·python
wniuniu_17 小时前
ceph的参数
java·数据库·ceph
一只专注api接口开发的技术猿17 小时前
智能决策数据源:利用 1688 商品详情 API 构建实时比价与供应链分析系统
大数据·前端·数据库
山峰哥17 小时前
SQL查询优化秘籍:从Explain分析到性能飞跃
开发语言·数据库·sql·oracle·性能优化·系统优化
刘一说17 小时前
MySQL 版本演进全景图:从 5.6 到 8.4 的技术变革与行业实践
数据库·mysql
风跟我说过她17 小时前
HBase完全分布式部署详细教程(含HA高可用版+普通非HA版)
大数据·数据库·分布式·centos·hbase