Redis-缓存击穿-逻辑过期

news2024/11/26 10:39:17

Redis-缓存击穿-逻辑过期实现

缓存击穿:也称热点key问题,大量访问一个key,而这个key恰巧到期了,导致大量的请求访问数据库。增大数据库的负担。为了解决这个问题可以采用互斥锁或逻辑过期的方式解决。本章采用逻辑过期的方式解决此问题。

流程图:

第一点需要进行缓存预热,把经常用的key预先缓存到redis中

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

    /** 缓存数据KEY */
    private final String CACHE_SHOP_KEY = "CACHE_SHOP_KEY:";
    /** 缓存互斥锁KEY */
    private final String CACHE_SHOP_LOCK_KEY = "CACHE_SHOP_LOCK_KEY:";

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    private static final ExecutorService CACHE_REBUILD_EXECUTOR = Executors.newFixedThreadPool(10);





/**
     * redis缓存
     * 缓存击穿
     */
    @Override
    public BooksVo selectById(Long bookId) {
        // 缓存击穿-互斥锁
        // return tryCacheMutex(bookId);

        // 缓存击穿-逻辑过期时间
        return tryCacheMutex2(bookId);
    }



/**
     * redis缓存
     * 缓存击穿-逻辑过期版本
     * @param bookId
     */
    private BooksVo tryCacheMutex2(Long bookId) {
        // RedisKey
        String cacheKey = CACHE_SHOP_KEY + bookId;
        // 1.从Redis查询商铺缓存
        // 获取缓存数据
        String contentBook = stringRedisTemplate.opsForValue().get(cacheKey);
        // 2.判断缓存是否命中
        if (StringUtils.isBlank(contentBook)){
            // 3.1缓存未命中 直接返回结果
            return null;
        }

       // 3.2缓存命中-获取数据
        RedisData redisData = JSONUtil.toBean(contentBook, RedisData.class);
        BooksVo booksVo = JSONUtil.toBean((JSONObject) redisData.getData(), BooksVo.class);
        LocalDateTime expireSecond = redisData.getExpireSecond();
        //  4.缓存未过期 直接返回数据
        if (expireSecond.isAfter(LocalDateTime.now())){
            return booksVo;
        }
        // 5.缓存过期-获取互斥锁
        if (tryLock(bookId)){
            // check double
            String s = stringRedisTemplate.opsForValue().get(cacheKey);
            RedisData redisData1 = JSONUtil.toBean(s, RedisData.class);
            if (BooleanUtil.isFalse(redisData1.getExpireSecond().isAfter(LocalDateTime.now()))){
                // 获取互斥锁成功,开启独立线程,缓存重建
                CACHE_REBUILD_EXECUTOR.submit(() -> {
                    try {
                        // 重建缓存
                        saveCacheBook(bookId, 20L);
                    } catch (Exception e) {
                        throw new RuntimeException(e);
                    } finally {
                        // 释放互斥锁
                        stringRedisTemplate.delete(CACHE_SHOP_LOCK_KEY + bookId);
                    }
                });
            }
        }
        // 返回已过期的数据
        return booksVo;
    }
                
                
                
     /**
     * 保存缓存信息
     */
    public void saveCacheBook(Long bookId, Long expireSeconds){
        // 1.查询数据库数据
        BooksVo booksVo = this.queryById(bookId);
        // 2.封装逻辑过期时间
        RedisData redisData = new RedisData();
        redisData.setData(booksVo);
        // 获取当前的时间 + 指定秒数
        redisData.setExpireSecond(LocalDateTime.now().plusSeconds(expireSeconds));
        // 3.写入redis
        stringRedisTemplate.opsForValue().set(CACHE_SHOP_KEY + bookId, JSONUtil.toJsonStr(redisData));
    }

redisData实体类

@Data
public class RedisData {
    /** 逻辑过期时间 */
    private LocalDateTime expireSecond;

    /** 拓展实体类 */
    private Object data;
}

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

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

相关文章

【Entity Framework】你知道如何处理无键实体吗

【Entity Framework】你知道如何处理无键实体吗 文章目录 【Entity Framework】你知道如何处理无键实体吗一、概述二、定义无键实体类型数据注释 三、无键实体类型特征四、无键实体使用场景五、无键实体使用场景六、无键使用示例6.1 定义一个简单的Blog和Post模型:6…

【Git】初识 Git

文章目录 1. 提出问题2. 如何解决?版本控制器3. 注意事项 1. 提出问题 不知道你工作或学习时,有没有遇到这样的情况:我们在编写各种文档时,为了防止文档丢失、更改失误、失误后能恢复到原来的版本,不得不复制出一个副…

TensorFlow实战 PDF书籍分享

今天又来给大家推荐一本大模型方面的书籍<TensorFlow实战>。《TensorFlow实战》希望用简单易懂的语言带领大家探索TensorFlow&#xff08;基于1.0版本API&#xff09;。 本书讲述了TensorFlow的基础原理&#xff0c;TF和其他框架的异同。并用具体的代码完整地实现了各种…

vue3 依赖-组件tablepage-vue3说明文档,列表页快速开发,使用思路及范例-汇总

github求⭐ 可通过github 地址和npm 地址查看全部内容,范例Ⅰ、Ⅱ、Ⅲ、Ⅳ免VIP查阅 vue3 依赖-组件tablepage-vue3说明文档,列表页快速开发,使用思路及范例(Ⅰ)配置项文档 vue3 依赖-组件tablepage-vue3说明文档,列表页快速开发,使用思路及范例(Ⅱ)搜索及数据获取…

[Java EE] 多线程(一) :线程的创建与常用方法(上)

1. 认识线程 1.1 概念 1.1.1 什么是线程 ⼀个线程就是⼀个"执⾏流".每个线程之间都可以按照顺序执⾏⾃⼰的代码.多个线程之间"同时"执⾏ 着多份代码. 还是回到我们之前的银⾏的例⼦中。之前我们主要描述的是个⼈业务&#xff0c;即⼀个⼈完全处理⾃⼰的…

十大排序——9.桶排序

这篇文章我们来介绍一下桶排序 目录 1.介绍 2.代码实现 3.总结与思考 1.介绍 桶排序和计数排序一样&#xff0c;都不是基于比较进行排序的。 下面通过一个例子来理解一下桶排序吧。 首先&#xff0c;给你一个无序数组[ 20,18,28,66,25,31,67,30 ]&#xff0c;然后&#…

CANoe中LIN工程主节点的配置(如何切换调度表)

1&#xff1a;前置条件 1&#xff09;工程已经建立&#xff0c;simulation窗口已经配置好&#xff08;包括且不限于通道mappin好&#xff0c;数据库文件已经添加&#xff09; 2&#xff09;我已系统自带sampleCfg工程&#xff0c;作为例子。如下图 2 &#xff1a;主节点的配置…

普发Pfeiffer CCR263 CCR272 CMR261 CMR273 PBR260 IMR265 TPR265 使用说明手侧

普发Pfeiffer CCR263 CCR272 CMR261 CMR273 PBR260 IMR265 TPR265 使用说明手侧

PhpStorm2024安装包(亲测可用)

目录 一、软件简介 二、软件下载 一、软件简介 PhpStorm是由JetBrains公司开发的一款商业的PHP集成开发环境&#xff08;IDE&#xff09;&#xff0c;深受全球开发人员的喜爱。它旨在提高开发效率&#xff0c;通过深刻理解用户的编码习惯&#xff0c;提供智能代码补全、快速导…

线程终止操作

关于线程的终止&#xff0c;我们有两种方法来实现 1.使用一个标志位 private static boolean flag true;public static void main(String[] args) throws InterruptedException {Thread t1 new Thread(() -> {while (flag) {System.out.println("你好");}});//…

【C语言】带你完全理解指针(五)练习

复习一下对数组名的理解 数组名的理解 数组名是数组首元素的地址 但是有2个例外&#xff1a; 1. sizeof(数组名)&#xff0c;这里的数组名表示整个数组&#xff0c;计算的是整个数组的大小&#xff0c;单位是字节 2. &数组名&#xff0c;这里的数组名表示整个数组&#xff…

《六》输入组控件InputWidget---Combo Box

一、Qt 输入组控件(Input Widgets&#xff09; Qt Input Widgets是一组用户界面元素&#xff0c;用于输入和显示文字和数字等的数据。这些小部件可以组成各种不同的表单和对话框&#xff0c;用户可以使用这些小部件与程序交互。 以下是Qt Input Widgets的一些常见小部件&…

L2-3 完全二叉树的层序遍历

完全二叉树的层序遍历 一个二叉树&#xff0c;如果每一个层的结点数都达到最大值&#xff0c;则这个二叉树就是完美二叉树。对于深度为 D 的&#xff0c;有 N 个结点的二叉树&#xff0c;若其结点对应于相同深度完美二叉树的层序遍历的前 N 个结点&#xff0c;这样的树就是完全…

跟着Datawhale重学数据结构与算法

数据结构和算法之前学过&#xff0c;现在跟着Datawhale重学一下&#xff0c;就当是监督自己学习&#xff0c;重新拾起来养成一个好的习惯&#xff0c;以后可以一直坚持下去。 开源链接&#xff1a;【 教程地址 】【电子网站】 首先&#xff1a; #mermaid-svg-Cdr3rn9fGCVAiKS…

STM32-ADC(独立模式、双重模式)

ADC简介 18个通道&#xff1a;外部信号源就是16个GPIO回。在引脚上直接接模拟信号就行了&#xff0c;不需要侄何额外的电路。引脚就直接能测电压。2个内部信号源是内部温度传感器和内部参考电压。 逐次逼近型ADC: 它是一个独立的8位逐次逼近型ADC芯片&#xff0c;这个ADC0809是…

C语言 | 自定义类型:联合和枚举

目录&#xff1a; ----前言 1. 联合体 1.1 联合体类型的声明 1.2 联合体的特点 1.3 相同成员的结构体和联合体对比 1.4 联合体大小的计算 1.5 联合的使用 1.6联合体的练习 2. 枚举 2.1 枚举类型的声明 2.2 枚举类型的优点 2.3 枚举类型的使用 --前言&#xff1a; c语言中内…

String类的几个常用方法

描述 以下程序演示了String类的几个常用方法&#xff0c;包括比较字符串、取得字符串长度、拆分字符串、获取子串、字符串转换成字符数组、获取字符串位置、替换字符串等方法。 案例 public class StringTest {public static void main(String[] args) {//比较字符串String …

阿赵UE学习笔记——28、粒子系统Niagara简介

阿赵UE学习笔记目录 大家好&#xff0c;我是阿赵。   继续学习虚幻引擎的使用。这次开始学习粒子系统的使用。 一、Cascade系统 在介绍UE5的Niagara系统之前&#xff0c;必须先介绍一下旧版本的粒子系统。   在UE4的时候&#xff0c;虚幻引擎的粒子系统叫做Cascade&#x…

ubuntu 使用conda 创建虚拟环境总是报HTTP错误,转换多个镜像源之后仍报错

最近在使用Ubuntu conda创建虚拟环境时&#xff0c;总是报Http错误&#xff0c;如下图所示&#xff1a; 开始&#xff0c;我以为是conda 镜像源的问题&#xff0c;但是尝试了好几个镜像源都不行&#xff0c;还是报各种各样的HTTP错误。后来查阅很多&#xff0c;总算解决了。解…

数学建模--深入剖析线性规划(模型全方位解读+代码分析)

1.简介 &#xff08;1&#xff09;线性规划三要素 &#xff08;2&#xff09;模型适用赛题 2.典例讲解 &#xff08;1&#xff09;问题分析 目标函数是净收益尽可能大&#xff0c;风险尽可能小&#xff1b; 约束条件是交易费的分段函数&#xff0c;以及每一笔投资都是非负数&am…