当前位置: 首页 > news >正文

【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.lryc.cn/news/265465.html

相关文章:

  • 系列一、GitHub搜索技巧
  • 35.java后端面试宝典
  • Linux 磁盘空间占满故障解决方法
  • 让生活更智能,P1600边缘智能网关带你进入智能家居新时代
  • Java与前端:2023年的真实状况与焦虑解读
  • adb 基本命令合集
  • [RK-Linux] RK3399支持M.2 NVMe SSD启动
  • LTO-3 磁带机种草终于是用上了
  • 【全网首发】洛谷P1020 [NOIP1999 提高组] 导弹拦截
  • trino-435版本windows下源码编译
  • java类和对象的思想概述
  • ant design vue3中引入message消息提示,全局引入亲测有效
  • UE5 Landscape 制作GIS卫星图地形
  • opencv入门到精通——改变颜色空间
  • 法线贴图实现地形模型皱褶、凹凸不平的纹理效果
  • 【SpringBoot篇】基于Redis实现生成全局唯一ID的方法
  • 轻度听力损失的儿童需要早期干预吗?
  • 【Spring Security】认证密码加密Token令牌CSRF的使用详解
  • python一点通: 一文讲清Post 和 Put操作区别!
  • 通过 Higress Wasm 插件 3 倍性能实现 Spring-cloud-gateway 功能
  • 0.618算法和基于Armijo准则的线搜索回退法
  • DPDK单步跟踪(3)-项目配置和单步跟踪
  • .NET core 自定义过滤器 Filter 实现webapi RestFul 统一接口数据返回格式
  • vue3 使用addRoute动态添加路由,页面刷新就白屏解决办法
  • 探索鸿蒙:了解华为鸿蒙操作系统的基础课程
  • 【Linux】进程周边007之进程控制
  • 【C++】vector容器的模拟实现
  • 华为Harmony——ArkTs语言
  • uniapp使用colorUI
  • 浅谈测试自动化selenium之POM模式