在SpringBoot中如何利用Redis实现互斥锁

 更新时间:2023年09月27日 11:25:00   作者:IDIOT___IDIOT  
当我们利用Redis存储热点数据时,突然就过期失效或者被删除了,导致大量请求同时访问数据库,增加了数据库的负载,为减轻数据库的负载我们利用互斥锁,本文重点介绍在SpringBoot中如何利用Redis实现互斥锁,感兴趣的朋友一起看看吧

在SpringBoot中利用Redis实现互斥锁

基本知识

前提条件,有一个能够在Springboot中使用Redis的项目,或者能够直接开也行

为什么要实现互斥锁:当我们利用Redis存储热点数据时,突然就过期失效或者被删除了,导致大量请求同时访问数据库,增加了数据库的负载。为减轻数据库的负载我们利用互斥锁。

业务的一个逻辑图流程:

在这里插入图片描述

核心思路:相较于原来从缓存中查询不到数据后直接查询数据库而言,现在的方案是 进行查询之后,如果从缓存没有查询到数据,则进行互斥锁的获取,获取互斥锁后,判断是否获得到了锁,如果没有获得到,则休眠,过一会再进行尝试,直到获取到锁为止(这个尝试,要重新从Redis再次尝试获取数据,可能别的锁已经获取到了),才能进行查询

如果获取到了锁的线程,再去进行查询,查询后将数据写入redis,再释放锁,返回数据,利用互斥锁就能保证只有一个线程去执行操作数据库的逻辑,防止缓存击穿

操作锁的核心思路就是利用redis的setnx方法来表示获取锁,该方法含义是redis中如果没有这个key,则插入成功,返回1

具体实现

设置锁,删除锁

   /**
     * 根据name对特定的数据进行锁
     * @param name
     * @return
     */
public boolean setLock(String name) {
    return Boolean.TRUE.equals(redisTemplate.opsForValue().setIfAbsent(name, true, 10, TimeUnit.SECONDS));
}
public boolean releaseLock(String name) {
    return Boolean.TRUE.equals(redisTemplate.delete(name));
}

具体流程实现

@GetMapping("/getOneByLock/{sequence}")
public BaseResponse<Sentences> getOneByLock(@PathVariable long sequence) {
    // 从redis中查信息
    String name = "test:redis:sentences:"+ sequence;
    Sentences sentence = (Sentences) redisTemplate.opsForValue().get(name);
    // 命中返回数据
    if(sentence != null ){
        redisTemplate.expire(name,2,TimeUnit.MINUTES);
        return ResultUtils.success(sentence);
    }
    // 未命中获取锁
    String LOCK_NAME = "test:redis:lock:" + sequence;
    boolean lock = redisTemplate.opsForValue().get(LOCK_NAME) != null && (boolean) redisTemplate.opsForValue().get(LOCK_NAME);
    //如果lock等于false 那么就可以获取到锁并且,锁住不许其他人操作
    if(!lock){
       return ResultUtils.success(setLockReleaseLockAboutSentence(LOCK_NAME,name,sequence));
    }
    // 没有获取到锁 休眠一段时间,并且反复检测redis中的数据是否存在,或者锁是否释放
    while(true){
        try {
            Thread.sleep(1000);
            log.error("等待中");
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        // 检查是否存在值
        sentence =  (Sentences) redisTemplate.opsForValue().get(name);
        if(sentence != null){
            return ResultUtils.success(sentence);
        }
        boolean checkAgain = (boolean) redisTemplate.opsForValue().get(LOCK_NAME);
        if(!checkAgain){
            sentence =  setLockReleaseLockAboutSentence(LOCK_NAME,name,sequence);
        }
        return ResultUtils.success(sentence);
    }
}
public Sentences setLockReleaseLockAboutSentence(String LOCK_NAME,String redisName, long sequence){
    // 设置 锁值 为true
    setLock(LOCK_NAME);
    // 并且从数据中查取数据
    Sentences sentence = sentencesService.getById(sequence);
    // 这里为了明显不能抢锁设置一个睡眠时间
    try {
        log.error("休眠中");
        Thread.sleep(3000);
    } catch (InterruptedException e) {
        throw new RuntimeException(e);
    }
//            把数据写入Redis
    redisTemplate.opsForValue().set(redisName,sentence,2, TimeUnit.MINUTES);
    // 释放锁
    releaseLock(LOCK_NAME);
    // 返回数据
    return sentence;
}

代码说明,在这个代码中为了演示明显,获取锁中延迟3s,竞争锁会延迟1s,下面的演示,初始时Redis中没有数据,只能去数据库中取数据,但是设置了互斥锁,所以只能够一个线程进入数据库取数据,其他只能等待数据得到结果。

结果示意 redis中无数据

在这里插入图片描述

结果

在这里插入图片描述

最终效果是好的。redis中已存入数据

到此这篇关于在SpringBoot中利用Redis实现互斥锁的文章就介绍到这了,更多相关SpringBoot互斥锁内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 在eclipse中使用SVN的方法(图文)

    在eclipse中使用SVN的方法(图文)

    这篇文章主要介绍了在eclipse中使用SVN的方法(图文),文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-08-08
  • Java中ArrayList的使用方法简单介绍

    Java中ArrayList的使用方法简单介绍

    这篇文章主要为大家简单介绍了Java中ArrayList的使用方法,针对ArrayList去重问题进行扩展分析,感兴趣的小伙伴们可以参考一下
    2016-07-07
  • 使用SpringSecurity 进行自定义Token校验

    使用SpringSecurity 进行自定义Token校验

    这篇文章主要介绍了使用SpringSecurity 进行自定义Token校验操作,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-06-06
  • SpringBoot 将配置文件挂到 jar 包外面的操作方法

    SpringBoot 将配置文件挂到 jar 包外面的操作方法

    在 SpringBoot 中,可以将配置文件放在 jar 包外面,这样可以方便地修改配置而不需要重新打包和部署,这篇文章主要介绍了SpringBoot 如何将配置文件挂到 jar 包外面,需要的朋友可以参考下
    2023-03-03
  • java Class文件内部结构解析过程详解

    java Class文件内部结构解析过程详解

    java class的文件结构,java class文件结构是基于字节流的,用unicode进行编码,下面说说java Class文件内部结构分析
    2013-11-11
  • 使用Java第三方实现发送短信功能

    使用Java第三方实现发送短信功能

    这篇文章主要介绍了使用Java第三方实现发送短信功能,在一些开发中,经常需要有给用户发送短信接收验证码的功能,那么在Java中该如何实现呢,今天我们就一起来看一看
    2023-03-03
  • 基于sharding-jdbc的使用限制

    基于sharding-jdbc的使用限制

    这篇文章主要介绍了sharding-jdbc的使用限制,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-10-10
  • Java数据结构之复杂度篇

    Java数据结构之复杂度篇

    算法复杂度分为时间复杂度和空间复杂度。其作用: 时间复杂度是度量算法执行的时间长短;而空间复杂度是度量算法所需存储空间的大小
    2022-01-01
  • Mybatis-flex整合达梦数据库的实现示例

    Mybatis-flex整合达梦数据库的实现示例

    本文讨论了国产达梦数据库与Mybatis-flex框架的整合过程,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2024-10-10
  • Spring cloud 查询返回广告创意实例代码

    Spring cloud 查询返回广告创意实例代码

    在本篇文章里小编给大家整理的是关于Spring cloud 查询返回广告创意实例代码,需要的朋友们可以跟着学习下。
    2019-08-08

最新评论