缓存穿透,缓存雪崩,使用互斥锁解决缓存击穿

20240716学习redis

  • 一、缓存穿透
    • 1. isNotBlank()方法和isNotEmpty()方法的区别
    • 2. 缓存穿透
    • 3. 缓存雪崩
    • 4. 缓存击穿的解决
    • 5 ctrl+alt+T,可以快速生成包围方式:
    • 6 //模拟重建延时
    • 7. 代码 (使用互斥锁)

一、缓存穿透

1. isNotBlank()方法和isNotEmpty()方法的区别

在常见的 Java 编程语言中,isNotBlank() 和 isNotEmpty() 方法通常用于判断字符串是否为空。它们通常用于 Apache Commons StringUtils 库中。

isNotBlank() 方法用于判断一个字符串是否有值并且不是全由空格组成。
如果字符串为 null,或者为空字符串 “”,或者只包含空格字符,则 isNotBlank() 方法会返回 false。
如果字符串不为 null 且长度大于 0,并且至少包含一个非空格字符,则 isNotBlank() 方法会返回 true。

isNotEmpty() 方法用于判断一个字符串是否不为空。
如果字符串为 null,或者为空字符串 “”,则 isNotEmpty() 方法会返回 false。
如果字符串不为 null 且长度大于 0,则 isNotEmpty() 方法会返回 true。

因此,两者的区别在于对空格字符的处理。isNotBlank() 方法会额外检查字符串中是否有非空格字符,而 isNotEmpty() 方法仅判断字符串是否为空或为 null。

2. 缓存穿透

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

在这里插入图片描述

3. 缓存雪崩

在这里插入图片描述

4. 缓存击穿的解决

在这里插入图片描述
可以通过和setnx一样的思路
在这里插入图片描述

5 ctrl+alt+T,可以快速生成包围方式:

在这里插入图片描述

6 //模拟重建延时

        Thread.sleep(200);这是 Java Thread 类中的一个静态方法。它使当前线程暂停(或休眠)指定的时间。
        下面就是我们的互斥锁的使用和定义了。

7. 代码 (使用互斥锁)

package com.hmdp.service.impl;

import cn.hutool.core.util.BooleanUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.hmdp.dto.Result;
import com.hmdp.entity.Shop;
import com.hmdp.mapper.ShopMapper;
import com.hmdp.service.IShopService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;

import java.util.concurrent.TimeUnit;

import static com.hmdp.utils.RedisConstants.CACHE_SHOP_KEY;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author 虎哥
 * @since 2021-12-22
 */
@Service
public class ShopServiceImpl extends ServiceImpl<ShopMapper, Shop> implements IShopService {

    @Resource
    private StringRedisTemplate stringRedisTemplate;
    @Override
    public Result queryById(Long id) {//首先,根据id在redis中查询店铺缓存
        //缓存穿透
       // Shop shop = queryWithPassThrough(id);

        //用互斥锁解决缓存击穿
        Shop shop = queryWithMutex(id);
        if (shop == null) {
            return Result.fail("店铺不存在");
        }

        //7.然后返回。
        return Result.ok(shop);
    }

    public Shop queryWithMutex(Long id){//互斥锁
        String key =CACHE_SHOP_KEY + id;    //定义一个key,包装id和一个字段名
        //1.从redis中查询商铺缓存
        String shopJson = stringRedisTemplate.opsForValue().get(key);//存的是一个对象可以用哈希,也可以用String,这里用hash演示
        //2.判断是否存在
        if (StrUtil.isNotBlank(shopJson)) {//isNotBlank只有里面有字符的时候才是true,null和空或者/n都为空false
            //3.存在,直接返回
            //把JSON对象转化为shop对象
            return JSONUtil.toBean(shopJson, Shop.class);
        }
        //判断命中的是否是空值
        if (shopJson != null) {
            //返回一个错误信息
            return null;
        }
        //4.开始实现缓存重建
        //4.1 获取互斥锁
        String lockKey = "lock:shop:" + id;    //定义一个key,包装id和一个字段名
        Shop shop = null;
        try {
            boolean isLock = tryLock(lockKey);
            //4.2 判断是否获取成功
            if(isLock){
                //4.3 失败,则休眠并重试
                Thread.sleep(50);
             return    queryWithMutex(id);
            }
            //4.3 失败,则休眠并重试
            //4.4不存在,根据id查询数据库
            shop = getById(id);
            //模拟重建延时
            Thread.sleep(200);
            //5.不存在,返回错误
            if (shop == null) {
                //将空值,写入redis
                stringRedisTemplate.opsForValue().set(key,"null",2L, TimeUnit.MINUTES);
                //返回错误信息
                return null;
            }
            //6.存在,把数据写入redis,
            stringRedisTemplate.opsForValue().set(key,JSONUtil.toJsonStr(shop),30L, TimeUnit.MINUTES);//
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }finally {
            //7.释放互斥锁
            unlock(lockKey);
        }

        //8.然后返回。
        return shop;
    }

    public Shop queryWithPassThrough(Long id){
        String key =CACHE_SHOP_KEY + id;    //定义一个key,包装id和一个字段名
        //1.从redis中查询商铺缓存
        String shopJson = stringRedisTemplate.opsForValue().get(key);//存的是一个对象可以用哈希,也可以用String,这里用hash演示
        //2.判断是否存在
        if (StrUtil.isNotBlank(shopJson)) {//isNotBlank只有里面有字符的时候才是true,null和空或者/n都为空false
            //3.存在,直接返回
  //把JSON对象转化为shop对象
            return JSONUtil.toBean(shopJson, Shop.class);
        }
        //判断命中的是否是空值
        if (shopJson != null) {
            //返回一个错误信息
            return null;
        }
        //4.不存在,根据id查询数据库
        Shop shop = getById(id);
        //5.不存在,返回错误
        if (shop == null) {
            //将空值,写入redis
            stringRedisTemplate.opsForValue().set(key,"null",2L, TimeUnit.MINUTES);
            //返回错误信息
            return null;
        }
        //6.存在,把数据写入redis,
        stringRedisTemplate.opsForValue().set(key,JSONUtil.toJsonStr(shop),30L, TimeUnit.MINUTES);//
        //7.然后返回。
        return shop;
    }

    //拿到锁
    private boolean tryLock(String key) {
        Boolean flag = stringRedisTemplate.opsForValue().setIfAbsent(key, "1", 10, TimeUnit.SECONDS);//相当于setnx
    return BooleanUtil.isTrue(flag);//判断是否成功,因为直接返回可能会导致拆箱
    }
    //释放锁
    private void unlock(String key){
        stringRedisTemplate.delete(key);
    }
    @Override
    @Transactional
    public Result update(Shop shop) {
        Long id = shop.getId();
        if (id == null) {
            return Result.fail("店铺id不能为空");
        }
        //1.更新数据库
        updateById(shop);
        //2.删除缓存
        stringRedisTemplate.delete(CACHE_SHOP_KEY + id);
        //3.返回结果
        return Result.ok();
    }
}

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Linux系统编程-线程同步详解

线程同步是指多个线程协调工作&#xff0c;以便在共享资源的访问和操作过程中保持数据一致性和正确性。在多线程环境中&#xff0c;线程是并发执行的&#xff0c;因此如果多个线程同时访问和修改共享资源&#xff0c;可能会导致数据不一致、竞态条件&#xff08;race condition…

15 - matlab m_map地学绘图工具基础函数 - 一些数据转换函数(二)

15 - matlab m_map地学绘图工具基础函数 - 一些数据转换函数&#xff08;二&#xff09; 0. 引言1. 关于m_geodesic2. 关于mygrid_sand23. 结语 0. 引言 通过前面篇节已经将m_map绘图工具中大多绘图有关的函数进行过介绍&#xff0c;已经能够满足基本的绘图需求&#xff0c;本节…

我想做信号通路分析,但我就是不想学编程

“我想做信号通路分析&#xff0c;但我就是不想学编程。” “我又不是生信狗&#xff0c;学代码会死。” “你们这些做生信的&#xff0c;整天把数据分析搞得神神秘秘&#xff0c;不就是怕被人抢饭碗而已嘛。” “这都没分析出我想要的结果&#xff0c;不靠谱。” “你们做…

Go语言中GC(垃圾回收回收机制)三色标记与混合写屏障

5、Golang三色标记混合写屏障GC模式全分析 (yuque.com) 第1讲-课程目标_哔哩哔哩_bilibili Golang三色标记GC混合写屏障 Go V1.3之前的标记清除&#xff08;mark and sweep) 垃圾回收、内存管理、自动适放、三色标记法、STW (stop the world) 图的遍历&#xff1f;可达性分…

路网双线合并单线——ArcGISpro 解决方法

路网双线合并成单线是一个在地图制作、交通规划以及GIS分析中常见的需求。双线路网定义&#xff1a;具有不同流向、不同平面结构的道路。此外&#xff0c;车道数较多的道路&#xff08;例如&#xff0c;双黄实线车道数大于4的道路&#xff09;也可以视为双线路网&#xff0c;本…

走,戴上你的旅行搭子去探险吧

如今快节奏的生活经常会让人感到疲惫和压力&#xff0c;炎炎夏日&#xff0c;一直想给自己松松绑&#xff01; 最近我和我的的小伙伴们去户外探险了&#xff0c;三五好友&#xff0c;组队出去玩&#xff0c;真的很让人放松&#xff01;一起去户外呼吸大自然的空气&#xff0c;…

【Hot100】LeetCode—155. 最小栈

目录 题目1- 思路2- 实现⭐155. 最小栈——题解思路 3- ACM 实现 题目 原题连接&#xff1a;155. 最小栈 1- 思路 思路 最小栈 ——> 借助两个栈来实现 2- 实现 ⭐155. 最小栈——题解思路 class MinStack {Stack<Integer> data;Stack<Integer> min;public …

VUE:跨域配置代理服务器

//在vite.config。js中&#xff0c;同插件配置同级进行配置server:{proxy:{"/myrequest":{//代理域名&#xff0c;可自行修改target:"https://m.wzj.com/",//访问服务器的目标域名changeOrigin:true,//允许跨域configure:(proxy,options) > {proxy.on(&…

图片常用的压缩方法,适用多种常用图片格式

jpg、png、jpeg、gif等图片格式是日常最常用的三种图片类型&#xff0c;一般在使用或者上传图片的时候这几种是比较常用的格式。在使用图片的时候&#xff0c;最常见的一个问题就是图片太大需要缩小后才可以正常使用&#xff0c;那么有什么方法或者工具能够快速处理不同图片格式…

在Mac上免费恢复已删除的PowerPoint文件

Microsoft PowerPoint for Mac 允许您在 macOS 环境中访问您熟悉的 PowerPoint 工具。该软件是Mac版Microsoft Office套件的一部分&#xff0c;具有各种稳定版本&#xff0c;即。PowerPoint 2019、2016、2011 等 PowerPoint for Mac 与 Apple 自己的演示应用程序 Keynote 兼容…

组网升级,双击热备和宽带管理

拓扑 要求&#xff1a; 要求12&#xff1a; 要求13&#xff1a; 要求14&#xff1a; 要求15&#xff1a; 要求16&#xff1a;

记录些MySQL题集(2)

MySQL 不使用limit的分页查询 limit问题&#xff1a;limit&#xff0c;offset递增问题。随着offset的增加&#xff0c;条数不变&#xff0c;耗时却增加了。 limit 0,10 耗时1ms limit 300000,10 耗时152ms limit 600000,10 耗时312ms 毫秒级别可能没感觉。假…

netdata 监控软件安装与学习

netdata官网 netdata操作文档 前言&#xff1a; netdata是一款监控软件&#xff0c;可以监控多台主机也可以监控单台主机&#xff0c;监控单台主机时&#xff0c;开箱即用&#xff0c;web ui很棒。 环境&#xff1a; [root192 ~]# cat /etc/system-release CentOS Linux rel…

工业大数据是什么?应用工业大数据时面临哪些挑战?

在当今快速发展的工业领域&#xff0c;大数据已成为推动企业转型升级的核心动力。工业大数据&#xff0c;以其独特的价值和潜力&#xff0c;正逐渐改变着传统的生产、管理和决策模式。然而&#xff0c;伴随着大数据的快速发展&#xff0c;一系列挑战也随之浮现。本文将深入探讨…

玻璃透过率太阳光辐射系统模拟器

太阳光模拟器概述 太阳光模拟器是一种先进的实验室设备&#xff0c;它能模拟太阳光的全光谱辐射&#xff0c;包括紫外线、可见光和红外线&#xff0c;用以评估材料、产品或设备在太阳辐射影响下的性能和耐久性。太阳光模拟器在多个领域有着广泛的应用&#xff0c;如光伏电池测…

【GD32】从零开始学GD32单片机 | WDGT看门狗定时器+独立看门狗和窗口看门狗例程(GD32F470ZGT6)

1. 简介 看门狗从本质上来说也是一个定时器&#xff0c;它是用来监测硬件或软件的故障的&#xff1b;它的工作原理大概就是开启后内部定时器会按照设置的频率更新&#xff0c;在程序运行过程中我们需不断地重装载看门狗&#xff0c;以使它不溢出&#xff1b;如果硬件或软件发生…

书生大模型实战营-入门岛-第3关

Python Python实现wordcount import string def wordcount(text):# 去除标点符号translator str.maketrans(, , string.punctuation)text text.translate(translator)# 将所有单词转换为小写text text.lower()# 将文本分割为单词列表words text.split()# 统计每个单词出现…

Webpack看这篇就够了

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 非常期待和您一起在这个小…

python项目读取oracle数据库方法(cx_Oracle库实现)

目录 创建一个python项目&#xff0c;并配置运行环境 查看oracle对应数据库版本&#xff08;该标题下内容只是为了查看版本&#xff0c;不用在意&#xff09; 从oracle官网下载对应版本的oracle客户端 解压下载的压缩包&#xff0c;并获取依赖 将依赖文件导入python项目运…

护眼台灯真的有用吗?一文搞懂台灯怎么选对眼睛好

现在我们很多家长对自己孩子的视力十分关心&#xff0c;生怕自己的孩子是近视、远视、弱视等等。对于父母而言&#xff0c;在孩子读书压力大课业重的关键时期&#xff0c;为孩子选择合适的学习桌椅、护眼灯从而保护孩子的眼睛是非常重要的事情!那么买给孩子学习的台灯又该注意哪…