【SpringBoot篇】解决缓存击穿问题① — 基于互斥锁方式

文章目录

  • 🌹什么是缓存击穿
  • 🌺基于互斥锁解决问题
    • 🛸思路
  • 🏳️‍🌈代码实现

在这里插入图片描述

🌹什么是缓存击穿

缓存击穿是指在使用缓存系统时,对一个热点数据的高并发请求导致缓存失效,多个请求同时访问数据库,造成数据库压力过大,性能下降。

具体来说,缓存击穿通常发生在以下情况下:

  • 热点数据失效:当某个热点数据的缓存过期或被删除时,此时如果有大量的并发请求同时访问该数据,缓存系统无法命中缓存,每个请求都会直接访问数据库。
  • 频繁更新数据:某个数据被频繁地修改,导致缓存频繁失效,而此时大量的请求同时访问该数据,造成缓存击穿。

缓存击穿会严重影响系统的性能和可用性,因为数据库无法处理如此高的并发请求,导致系统响应变慢甚至崩溃。

但是对于缓存击穿,我们有什么方法可以解决呢

🌺基于互斥锁解决问题

互斥锁(Mutex)是一种并发编程中用于保护共享资源的机制,它可以确保在同一时刻只有一个线程可以访问共享资源,从而避免多个线程同时对共享资源进行读写操作而导致的数据竞争和不确定性行为。

互斥锁的主要特点包括:

  • 独占性:当一个线程获得了互斥锁后,其他线程就无法再获得该互斥锁,直到持有该锁的线程释放它。
  • 阻塞和等待:如果一个线程尝试获取已被其他线程持有的互斥锁,那么它会被阻塞,直到该互斥锁被释放。
  • 原子性:互斥锁的获取和释放操作是原子的,不会被打断。

互斥锁通常用于以下场景:

  • 在多线程环境下保护共享资源,如共享变量、共享数据结构等,防止多个线程同时修改造成数据不一致。
  • 控制对临界区的访问,确保同一时间只有一个线程能够执行临界区代码,以避免竞态条件(Race Condition)的发生。

🛸思路

使用互斥锁来解决缓存击穿问题的思路是通过对关键代码块进行加锁保证在同一时间只有一个线程能够执行这段代码。这样可以有效地避免多个线程同时访问数据库,减轻数据库的压力,提高系统的性能和可用性。

在解决缓存击穿问题时,通常会使用互斥锁锁住以下几个关键步骤:

  • 检查缓存:首先检查缓存中是否存在所需数据。
  • 缓存失效处理:如果缓存中不存在所需数据,即缓存失效,需要进行进一步处理。
  • 加锁:在进行缓存失效处理之前,获取互斥锁,确保只有一个线程能够执行后续的数据库查询和缓存更新操作。
  • 数据查询和缓存更新:在成功获得互斥锁之后,执行数据库查询操作,获取所需数据,并将数据更新到缓存中。
  • 释放锁:缓存更新完成后,释放互斥锁,允许其他等待的线程获得锁并从缓存中获取数据。

通过加锁的方式,保证了同一时间只有一个线程能够执行关键代码块,避免了缓存击穿问题。其他线程在等待期间可以从缓存中获取旧数据,而不会直接访问数据库。这样可以减少数据库的并发访问压力,提升了系统的并发能力和性能。

需要注意的是,互斥锁的使用应该谨慎,避免持有锁的时间过长,否则可能会导致其他线程的延迟和性能下降。在设计时,要权衡锁的粒度和性能需求,确保互斥锁的使用场景合理,并根据具体情况选择合适的锁机制(如读写锁、分布式锁等)进行优化。

🏳️‍🌈代码实现

我们看下面的例子
请添加图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

@Service
public class ShopServiceImpl extends ServiceImpl<ShopMapper, Shop> implements IShopService {@Resourceprivate StringRedisTemplate stringRedisTemplate;@Overridepublic Result queryById(Long id) {//缓存穿透
//        Shop shop=queryWithPassThrough(id);//互斥锁解决缓存击穿Shop shop=queryWithMutex(id);if(shop==null){return Result.fail("店铺不存在");}//返回return Result.ok(shop);}public Shop queryWithMutex(Long id){String key=CACHE_SHOP_KEY+":"+id;//从redis中查询缓存String shopJson=stringRedisTemplate.opsForValue().get(key);//判断是否存在if(StrUtil.isNotBlank(shopJson)){//存在,直接返回return JSONUtil.toBean(shopJson, Shop.class);}//判断命中的是否是空值if(shopJson!=null){//返回一个错误信息return null;}//实现缓存重建//获取互斥锁String lockKey="lock:shop"+id;Shop shop=null;try {boolean isLock=tryLock(lockKey);//判断是否获取成功if (!isLock){//失败,那么休眠并且重试Thread.sleep(100);return queryWithMutex(id);}//成功,则根据id查询数据库shop=getById(id);//不存在,返回错误if(shop==null){//将空值写入到redisstringRedisTemplate.opsForValue().set(key,JSONUtil.toJsonStr(shop),CACHE_SHOP_TTL,TimeUnit.MINUTES);return null;}//存在,写入到redis里面stringRedisTemplate.opsForValue().set(key,JSONUtil.toJsonStr(shop),CACHE_SHOP_TTL,TimeUnit.MINUTES);}catch (Exception e){throw new RuntimeException(e);}finally {//释放互斥锁unlock(lockKey);}//返回return shop;}//存在,写入到redis里面stringRedisTemplate.opsForValue().set(key,JSONUtil.toJsonStr(shop),CACHE_SHOP_TTL,TimeUnit.MINUTES);//返回return shop;}//获取锁private boolean tryLock(String key){Boolean flag = stringRedisTemplate.opsForValue().setIfAbsent(key, "1", 10, TimeUnit.SECONDS);return BooleanUtil.isTrue(flag);}//释放锁private void unlock(String key){stringRedisTemplate.delete(key);}
}

在技术的道路上,我们不断探索、不断前行,不断面对挑战、不断突破自我。科技的发展改变着世界,而我们作为技术人员,也在这个过程中书写着自己的篇章。让我们携手并进,共同努力,开创美好的未来!愿我们在科技的征途上不断奋进,创造出更加美好、更加智能的明天!

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/292108.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

anconda常用命令

一、基础指令说明 1、查看anconda版本号 conda --version 2、查看当前已有虚拟环境 conda env list 3、创建新环境 conda create -n classify python3.9 创建一个叫做classify的虚拟环境&#xff0c;其中python等于3.9 4、进入虚拟环境 activate classify 5、安装包 接下来…

【数据结构】四、串

目录 一、定义 二、表示与实现 定长顺序存储 堆分配存储 链式存储 三、BF算法 四、KMP算法 1.求next数组 方法一 方法二&#xff08;考试方法&#xff09; 2.KMP算法实现 方法一 方法二 3.nextval 4.时间复杂度 本节最重要的就是KMP算法&#xff0c;其他要求不高…

电脑怎么重装系统?跟着步骤轻松搞定!

电脑系统随着时间的推移可能会变得迟缓或出现其他问题&#xff0c;而重装系统是解决这些问题的有效方法之一。本文将介绍三种电脑怎么重装系统的方法&#xff0c;帮助您在不同情况下选择适合自己的方案&#xff0c;让电脑焕然一新。 方法1&#xff1a;使用系统自带的恢复选项 …

4. 行为模式 - 中介者模式

亦称&#xff1a; 调解人、控制器、Intermediary、Controller、Mediator 意图 中介者模式是一种行为设计模式&#xff0c; 能让你减少对象之间混乱无序的依赖关系。 该模式会限制对象之间的直接交互&#xff0c; 迫使它们通过一个中介者对象进行合作。 问题 假如你有一个创建…

基于Java SSM框架实现人事员工考勤签到请假管理系统项目【项目源码+论文说明】

基于java的SSM框架实现人事员工考勤签到请假管理系统演示 摘要 在高速发展的时代&#xff0c;众多的软件被开发出来&#xff0c;给用户带来了很大的选择余地&#xff0c;而且人们越来越追求更个性的需求。在这种时代背景下&#xff0c;人们对人事管理系统越来越重视&#xff0…

STL--stack、queue实现

STL中&#xff0c;vector、list 是容器&#xff0c;自己存储一系列的数据进行增删查改&#xff0c;而 stack、queue 是一种特殊的容器&#xff0c;叫容器适配器&#xff0c;提供一种特定的接口来访问底层容器。 STL--stack实现 template<class T, class Container deque&…

Altium Designer软件界面切换为浅灰色与深灰色的方法图文教程及视频演示

目录 视频演示1&#xff0c;概述2&#xff0c;切换方法3&#xff0c;总结 视频演示 Altium Designer软件界面切换方法演示 欢迎点击浏览更多高清视频演示 1&#xff0c;概述 Altium Designer软件界面主题色调的切换&#xff0c;本文演示Altium Designer软件切换为浅灰色和深灰色…

折线图——根据时间间隔X轴不等间距展示

折线图——根据时间间隔X轴不等间距展示 option option {"title": {"text": "X轴不等间距分布","left": "center","textStyle": {"fontSize": 14}},"tooltip": {"trigger": &quo…

Gartner2023数据库魔力象限发布 阿里云依旧领导者 腾讯退出 EDB/Yugabyte进入

这是一个跨越数年的系列&#xff0c;历史文章参考&#xff1a; * 数据库魔力象限2022&#xff1a;阿里领先、腾讯再次进入 * 2021 藏在魔力象限中的数据库江湖 * Gartner云计算魔力象限2018 概述 Gartner云数据库魔力象限&#xff08;后简称“象限”或“MQ”&#xff09;一…

【数字图像处理】实验四 图像分割

一、实验内容&#xff1a; 1&#xff0e; 熟悉和掌握利用Matlab工具进行数字图像的读、写、显示等数字图像处理基本步骤。 2&#xff0e; 熟练掌握各种图像分割的基本原理及方法。 3&#xff0e; 能够从深刻理解图像分割&#xff0c;并能够思考拓展到一定的应用领域。 二、实验…

谈谈 tcp 慢启动与拥塞控制

慢启动是一种 capacity-search 策略&#xff0c;不限于 tcp&#xff0c;但不说 tcp 慢启动不配标题党&#xff0c;所以就说 tcp 慢启动。 慢启动用指数灌报文的方式快速探测网络容量&#xff0c;所谓 “慢” 是起点慢。值得注意的是&#xff0c;传统慢启动不做 pacing&#xf…

从DevOps状态报告看技术团队的文化建设

本文源自一次内部分享&#xff0c;借由此机会又把历年的DevOps状态报告翻看了一遍&#xff0c;其实大多数时候我们对于DevOps的理解都在于流程&#xff0c;工具&#xff0c;实践这些看得见摸得着的东西&#xff0c;但就像文末的几点思考所说的那样&#xff0c;我们一直相信技术…