免费网站空间哪个好,北京做网站制作的公司,seo课,软件项目管理期末考试在SpringBoot中利用Redis实现互斥锁
基本知识 前提条件#xff0c;有一个能够在Springboot中使用Redis的项目#xff0c;或者能够直接开也行 为什么要实现互斥锁#xff1a;当我们利用Redis存储热点数据时#xff0c;突然就过期失效或者被删除了#xff0c;导致大量请求同…在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 BaseResponseSentences 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){// 设置 锁值 为truesetLock(LOCK_NAME);// 并且从数据中查取数据Sentences sentence sentencesService.getById(sequence);// 这里为了明显不能抢锁设置一个睡眠时间try {log.error(休眠中);Thread.sleep(3000);} catch (InterruptedException e) {throw new RuntimeException(e);}
// 把数据写入RedisredisTemplate.opsForValue().set(redisName,sentence,2, TimeUnit.MINUTES);// 释放锁releaseLock(LOCK_NAME);// 返回数据return sentence;
}代码说明在这个代码中为了演示明显获取锁中延迟3s竞争锁会延迟1s下面的演示初始时Redis中没有数据只能去数据库中取数据但是设置了互斥锁所以只能够一个线程进入数据库取数据其他只能等待数据得到结果。
结果示意
redis中无数据 结果 最终效果是好的。redis中已存入数据