SpringBoot整合Redis:缓存击穿--互斥锁解决

🎉🎉欢迎光临,终于等到你啦🎉🎉

🏅我是苏泽,一位对技术充满热情的探索者和分享者。🚀🚀

🌟持续更新的专栏Redis实战与进阶

本专栏讲解Redis从原理到实践

这是苏泽的个人主页可以看到我其他的内容哦👇👇

努力的苏泽icon-default.png?t=N7T8http://suzee.blog.csdn.net


最近超级无敌忙  就断更好久了  实在是抽不出时间来 没办法  这篇文章也只是整理我以前学习的资料  目前还有一整套企业级的Redis处理方案没写哈 敬请期待朋友们

下面是正文


目录

首先我们要明白什么是缓存击穿

分析有什么办法能解决

业务解析

​编辑

代码实现:

然后我们将缓存穿透的函数给封装起来

原函数

我们将这部分逻辑 封装到 queryWithPassThrough中

我们再写一个函数queryWithMutex来用互斥锁解决缓存穿透的问题

于是原本的查询函数的结构就变成了这样

这样做的优缺点

优点:

缺点:

下一篇我们来讲解如何使用另一个方案解决这个问题


首先我们要明白什么是缓存击穿

Redis缓存击穿是指在高并发的情况下,当某个热点数据的缓存过期或不存在时,大量的请求同时涌入数据库或后端服务,导致数据库或后端服务负载过高,甚至崩溃的情况。

分析有什么办法能解决

当涉及到并发访问共享资源时,互斥锁和逻辑过期是两种常用的技术手段。

  1. 互斥锁(Mutex):
    互斥锁是一种并发控制机制,用于在多个线程或进程之间保证共享资源的互斥访问。它通过在关键代码段前后设置锁来确保同一时间只有一个线程或进程可以执行关键代码段。当某个线程或进程获取到互斥锁时,其他线程或进程需要等待锁的释放才能继续执行。

业务解析

代码实现:

先写两个函数 一个加锁 一个释放锁

private boolean tryLock(String key){//自定义互斥锁  将申请锁的结果返回Boolean flag = stringRedisTemplate.opsForValue().setIfAbsent(key, "1", 10L, TimeUnit.SECONDS);return BooleanUtil.isTrue(flag);}
//释放锁
private void unLock(String key){stringRedisTemplate.delete(key);}

然后我们将缓存穿透的函数给封装起来

原函数

public Result queryById(Long id) {//1.从Redis查询id  这里使用的数据结构可以是String也可以是hash  若是查询不到就为空了 CACHE_SHOP_KEY就是"cache:shop:"String shopJson = stringRedisTemplate.opsForValue().get(CACHE_SHOP_KEY + id);//2.判断是否存在 在字符串意义上是否为空if (StrUtil.isNotBlank(shopJson)) {//3.存在直接返回Shop shop = JSONUtil.toBean(shopJson, Shop.class);return  Result.ok(shop);}//3.判断是否命中写入redis中的nullif(shopJson != null){return Result.fail("店铺信息不能为空!");}//4.不存在 查询数据库Shop shop = getById(id);//5.数据库中不存在 返回报错if (shop == null){//空值写入redisstringRedisTemplate.opsForValue().set("cache:shop:" + id, null,CACHE_NULL_TTL, TimeUnit.MINUTES);return Result.fail("店铺不存在!");}//6.数据库中存在  写入Redis  并返回stringRedisTemplate.opsForValue().set("cache:shop:" + id, JSONUtil.toJsonStr(shop),30L, TimeUnit.MINUTES);return Result.ok(shop);
}

我们将这部分逻辑 封装到 queryWithPassThrough中

//封装缓存穿透函数
private Shop queryWithPassThrough(Long id){//1.从Redis查询id  这里使用的数据结构可以是String也可以是hash  若是查询不到就为空了 CACHE_SHOP_KEY就是"cache:shop:"String shopJson = stringRedisTemplate.opsForValue().get(CACHE_SHOP_KEY + id);//2.判断是否 在字符串意义上是否为空if (StrUtil.isNotBlank(shopJson)) {//3.存在直接返回Shop shop = JSONUtil.toBean(shopJson, Shop.class);return  shop;}//3.判断是否命中写入redis中的nullif(shopJson != null){return null;}Shop shop = getById(id);//5.数据库中不存在 返回报错if (shop == null){//空值null写入redisstringRedisTemplate.opsForValue().set("cache:shop:" + id, null,CACHE_NULL_TTL, TimeUnit.MINUTES);return null;}//6.数据库中存在  写入Redis  并返回stringRedisTemplate.opsForValue().set("cache:shop:" + id, JSONUtil.toJsonStr(shop),30L, TimeUnit.MINUTES);return shop;
}

我们再写一个函数queryWithMutex来用互斥锁解决缓存穿透的问题

于是原本的查询函数的结构就变成了这样

public Result queryById(Long id) {//缓存穿透
//        Shop shop = queryWithPassThrough(id);//互斥锁解决缓存穿透Shop shop = queryWithMutex(id);if (shop == null) {return Result.fail("店铺不存在");}//返回return Result.ok(shop);}
//解决缓存穿透的问题
private Shop queryWithMutex(Long id) throws InterruptedException{String lockKey = "lockKey" + id;while (true) {//1.从Redis查询id  这里使用的数据结构可以是String也可以是hash  若是查询不到就为空了 CACHE_SHOP_KEY就是"cache:shop:"String shopJson = stringRedisTemplate.opsForValue().get(CACHE_SHOP_KEY + id);//2.判断是否 在字符串意义上是否为空if (StrUtil.isNotBlank(shopJson)) {//3.存在直接返回Shop shop = JSONUtil.toBean(shopJson, Shop.class);return  shop;}//3.判断是否命中写入redis中的nullif(shopJson != null){return null;}//4重建缓存//4.1申请互斥锁boolean flag = tryLock(lockKey);//4.2判断是否成功if (!flag){try {Thread.sleep(100);} catch (InterruptedException e) {throw new RuntimeException(e);}}else//成功了就跳出循环  这里不敢用递归 怕栈溢出了break;}//4.4 成功 查询数据库Shop shop = getById(id);//5.数据库中不存在 返回报错if (shop == null){//空值null写入redisstringRedisTemplate.opsForValue().set("cache:shop:" + id, null,CACHE_NULL_TTL, TimeUnit.MINUTES);return null;}//6.数据库中存在  写入Redis  并返回stringRedisTemplate.opsForValue().set("cache:shop:" + id, JSONUtil.toJsonStr(shop),30L, TimeUnit.MINUTES);//7.释放互斥锁unLock(lockKey);return shop;
}

这样做的优缺点

互斥锁作为一种并发控制机制,在解决缓存击穿问题时具有以下优点和缺点:

优点:

  1. 确保数据一致性:互斥锁可以确保同一时间只有一个线程或进程可以访问共享资源,避免了并发访问导致的数据不一致性问题。

  2. 避免竞态条件:互斥锁可以防止多个线程或进程同时执行关键代码段,避免了竞态条件的发生。竞态条件是指多个线程或进程对共享资源的访问顺序不确定,导致结果的不可预测性。

  3. 简单易用:互斥锁的使用相对简单,可以通过加锁和解锁操作来控制对共享资源的访问。

缺点:

  1. 性能开销:互斥锁在多线程环境下会引入一定的性能开销。当多个线程竞争同一个锁时,其他线程需要等待锁的释放,这会导致一些线程的阻塞和等待,降低系统的并发性能。

  2. 可能引发死锁:如果在使用互斥锁时处理不当,可能会发生死锁的情况。死锁是指多个线程或进程相互等待对方持有的资源,导致所有线程都无法继续执行。

  3. 容易导致线程饥饿:当某个线程持有互斥锁并长时间不释放时,其他线程可能会一直等待锁的释放,导致线程饥饿现象出现。

下一篇我们来讲解如何使用另一个方案解决这个问题

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

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

相关文章

数字时代的风向标:Facebook如何引领社交媒体的发展方向

引言 在当今数字时代,社交媒体已经成为人们生活中不可或缺的一部分,而Facebook作为其中的领军者,不仅影响着亿万用户的生活,也在塑造着整个社交媒体行业的发展方向。本文将深入探讨Facebook在数字时代的地位、影响力以及对社交媒…

3d放上模型为什么渲染不出来---模大狮模型网

如果在3D软件中放置模型后无法正确渲染出来,可能有几个常见的原因导致这种情况发生: 材质设置问题:确保所放置的模型具有正确的材质和纹理,并且材质设置正确。如果材质设置有误,可能会导致模型无法正确显示。 光照设置…

flink: 从pulsar中读取数据

一、依赖 <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http://maven.apache.org/POM/4.0.0…

配置小程序的服务器域名

准备工作 拥有一个已注册的域名&#xff1a;确保您已经注册了一个符合国家和地区相关法律法规要求的域名。 完成域名备案&#xff08;如有必要&#xff09;&#xff1a;根据国家和地区的法律法规&#xff0c;某些情况下可能需要对域名进行备案才能用于互联网服务。 配置 DNS&…

Vue 二次封装组件的艺术与实践

&#x1f90d; 前端开发工程师、技术日更博主、已过CET6 &#x1f368; 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 &#x1f560; 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 &#x1f35a; 蓝桥云课签约作者、上架课程《Vue.js 和 E…

备考ICA----Istio实验9---熔断Circuit Breaking 实验

备考ICA----Istio实验9—熔断Circuit Breaking 实验 1. 环境准备 创建httpbin环境 kubectl apply -f istio/samples/httpbin/httpbin.yaml kubectl get svc httpbin2. 创建测试用客户端 kubectl apply -f istio/samples/httpbin/sample-client/fortio-deploy.yaml3. 创建Ht…

python笔记进阶--模块、文件及IO操作(1)

目录 一&#xff0e;模块 1.模块的导入和使用 1.1导入整个模块 1.2导入函数 1.3使用as给模块指定别名 2.常见标准库 2.1 import random&#xff1a; 2.2 import math&#xff1a; 2.3正则表达式处理 2.4turtle 二&#xff0e;文件及IO操作 1.文件 1.1绝对路径与相…

Intellij IDEA 类注释模板设置

1、配置全局USER 在此配置全局USER&#xff0c;用于填充自动生成的注释中的作者author属性。 注释模板中的user参数是默认是获取系统的用户&#xff08;当然注释作者也可以直接写固定值&#xff09;&#xff0c;如果不想和系统用户用同一个信息&#xff0c;可以在IDEA中进行配…

【自我提升】一、Hyperledger Fabric 概念梳理

写在前面&#xff1a;最近因为业务需要&#xff0c;开始学习Hyperledger Fabric了&#xff0c;做java全栈工程师可真难搞。现在算是啥类型的都在涉及了&#xff0c;现在这个技术啥都不懂&#xff0c;就先开个学习专栏&#xff0c;记录记录。顺带也给各位道友参考参考。 目录 …

「媒体宣传」媒体邀约几种常见方法!-51媒体

传媒如春雨&#xff0c;润物细无声&#xff0c;大家好&#xff0c;我是51媒体网胡老师。 媒体邀约的常见方法确实包括电话邀约、邮件邀约、社交媒体邀约以及通过媒体公关公司代邀约等。 电话邀约&#xff1a;这是一种直接且高效的方式&#xff0c;可以通过电话与媒体记者沟通&…

HTTP请求走私!!!(一)

想都是问题&#xff0c;做才是答案 什么是请求走私&#xff1f; HTTP请求走私是针对于服务端处理一个或者多个接收http请求序列的方式&#xff0c;进行绕过安全机制&#xff0c;实施未授权访问一种攻击手段&#xff0c;获取敏感信息&#xff0c;并直接危害其他用户。 Web 应用…

【前端学习——css篇】4.px和rem的区别

https://github.com/febobo/web-interview 4.px和rem的区别 ①px px&#xff0c;表示像素&#xff0c;所谓像素就是呈现在我们显示器上的一个个小点&#xff0c;每个像素点都是大小等同的&#xff0c;所以像素为计量单位被分在了绝对长度单位中 有些人会把px认为是相对长度&…

大语言模型(LLM)token解读

1. 什么是token&#xff1f; 人们经常在谈论大模型时候&#xff0c;经常会谈到模型很大&#xff0c;我们也常常会看到一种说法&#xff1a; 参数会让我们了解神经网络的结构有多复杂&#xff0c;而token的大小会让我们知道有多少数据用于训练参数。 什么是token&#xff1f;比…

浅聊openGauss逻辑架构

浅聊 openGauss 逻辑架构 概述 openGauss 数据库是一款由华为主导、各个生态合作伙伴共同建设的开源关系型数据库管理系统&#xff0c;开源发行协议遵从木兰宽松许可证 v2。 openGauss 数据库源于 PostgreSQL-XC 项目&#xff0c;内核源于 Postgres 9.2.4&#xff0c;总代码…

mybatis注解方式if标签报错元素内容必须由格式正确的字符数据或标记组成

在使用mybatis的注解方式的时候出现个问题&#xff0c;我需要一个复杂的sql语句&#xff0c;既有if判断又有in语句&#xff0c;刚开始使用mybatis自己的if动态函数的时候完全没问题&#xff0c;代码如下&#xff1a; Select({"select * ","from order_info &qu…

利用python脚本,根据词条爬取百度图片(爬虫)

把广角&#xff0c;换成你的关键词就行 # -*- coding: utf-8 -*- """ Created on Wed Mar 29 10:17:50 2023 author: MatpyMaster """ import requests import os import redef get_images_from_baidu(keyword, page_num, save_dir):header {Us…

Hadoop+Spark大数据技术 第三次作业

第三次作业 1.简述HDFS Shell三种操作命令hadoop fs、hadoop dfs、hdfs dfs的异同点。 相同点 用于与 Hadoop 分布式文件系统&#xff08;HDFS&#xff09;交互。可以执行各种文件系统操作&#xff0c;如文件复制、删除、移动等。 不同点 hadoop fs、hadoop dfs已弃用&#xf…

使用vue构建一个简单实用的春节红包插件!

摘要&#xff1a;本文将介绍如何使用Vue.js构建一个简单实用的春节红包插件。该插件通过模拟红包的打开和关闭过程&#xff0c;以及金额的随机分配&#xff0c;为春节红包活动提供了一个有趣且互动的体验。 一、引言 在春节这个充满欢乐和祝福的时刻&#xff0c;红包成为了传递…

Encoding类

Encoding System.Text.Encoding 是 C# 中用于处理字符编码和字符串与字节之间转换的类。它提供了各种静态方法和属性&#xff0c;**用于在不同字符编码之间进行转换&#xff0c;**以及将字符串转换为字节数组或反之。 在处理多语言文本、文件、网络通信以及其他字符数据的场景…

node.js项目初始化操作

项目环境Vscode 1.新建一个文件夹node.js(xx.js) 2.右键点击node.js&#xff0c;点击打开终端 我在VScode打开终端 输入npm init初始化项目没反应。 解决方法&#xff1a;进入文件夹node.js&#xff0c;出入cmd跳转到终端 重新输入npm init命令 正确结果如下图 后续命令按下…