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

Spring Cache的基本使用与分析

概述

使用 Spring Cache 可以极大的简化我们对数据的缓存,并且它封装了多种缓存,本文基于 redis 来说明。

基本使用

1、所需依赖

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-cache</artifactId>
</dependency>

2、配置文件

spring:# redis连接信息redis:host: 192.168.56.10port: 6379cache:# 指定使用的缓存类型type: redis# 过期时间redis:time-to-live: 3600000# 是否开启前缀,默认为trueuse-key-prefix: true# 键的前缀,如果不配置,默认就是缓存名cacheNameskey-prefix: CACHE_# 是否缓存空置,防止缓存穿透,默认为truecache-null-values: true

3、Spring Cache 提供的注解如下,使用方法参见:官方文档,通过这些注解,我们可以方便的操作缓存数据。

  • @Cacheable:触发缓存写入的操作
  • @CacheEvict:触发缓存删除的操作
  • @CachePut:更新缓存,而不会影响方法的执行
  • @Caching:重新组合要应用于一个方法的多个缓存操作,即对一个方法添加多个缓存操作
  • @CacheConfig:在类级别共享一些与缓存有关的常见设置

例如,如果需要对返回结果进行缓存,直接在方法上标注 @Cacheable 注解(在主配置类上需要标注上 @EnableCaching

@Cacheable(cacheNames = "userList") //指定缓存的名字,便于区分不同缓存
public List<User> getUserList() {...
} 

4、redis 默认使用 jdk 序列化,需要我们配置序列化机制,自定义一个配置类,否则存入的数据显示乱码

@EnableCaching //开启缓存
@Configuration
public class MyCacheConfig {@Beanpublic RedisCacheConfiguration redisCacheConfiguration(){RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig();//指定键和值的序列化机制config = config.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()));config = config.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer()));return config;}
}

5、使用以上配置后,虽然乱码的问题解决了,但配置文件又不生效了,比如过期时间等,这是因为在初始化时会判断用户是否自定义了配置文件,如果自定义了,原来的就不会生效,源码如下:

private org.springframework.data.redis.cache.RedisCacheConfigurationdetermineConfiguration(ClassLoader classLoader) {//如果配置了,就返回自定义的配置if (this.redisCacheConfiguration != null) {return this.redisCacheConfiguration;}//没配置使用默认的配置Redis redisProperties = this.cacheProperties.getRedis();org.springframework.data.redis.cache.RedisCacheConfiguration config = org.springframework.data.redis.cache.RedisCacheConfiguration.defaultCacheConfig();config = config.serializeValuesWith(SerializationPair.fromSerializer(new JdkSerializationRedisSerializer(classLoader)));if (redisProperties.getTimeToLive() != null) {config = config.entryTtl(redisProperties.getTimeToLive());}if (redisProperties.getKeyPrefix() != null) {config = config.prefixKeysWith(redisProperties.getKeyPrefix());}if (!redisProperties.isCacheNullValues()) {config = config.disableCachingNullValues();}if (!redisProperties.isUseKeyPrefix()) {config = config.disableKeyPrefix();}return config;
}

6、所以,我们也需要手动获取 ttl、prefix 等属性,直接仿照源码就行,将配置类修改为如下:

@EnableCaching //开启缓存
@Configuration
@EnableConfigurationProperties(CacheProperties.class) //缓存的所有配置属性都在这个类里
public class MyCacheConfig {@Beanpublic RedisCacheConfiguration redisCacheConfiguration(CacheProperties cacheProperties) {//获取默认配置RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig();//指定键和值的序列化机制config = config.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()));config = config.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer()));//获取配置文件的配置CacheProperties.Redis redisProperties = cacheProperties.getRedis();if (redisProperties.getTimeToLive() != null) {config = config.entryTtl(redisProperties.getTimeToLive());}if (redisProperties.getKeyPrefix() != null) {config = config.prefixKeysWith(redisProperties.getKeyPrefix());}if (!redisProperties.isCacheNullValues()) {config = config.disableCachingNullValues();}if (!redisProperties.isUseKeyPrefix()) {config = config.disableKeyPrefix();}return config;}
}

原理分析

在 Spring 中 CacheManager 负责创建管理 Cache,Cache 负责缓存的读写,因此使用 redis 作为缓存对应的就有 RedisCacheManager 和 RedisCache。

打开 RedisCache 源码,我们需要注意这两个方法:

1、读取数据,未加锁

@Override
protected Object lookup(Object key) {byte[] value = cacheWriter.get(name, createAndConvertCacheKey(key));if (value == null) {return null;}return deserializeCacheValue(value);
}

2、读取数据,加锁,这是 RedisCache 中唯一一个同步方法

@Override
public synchronized <T> T get(Object key, Callable<T> valueLoader) {ValueWrapper result = get(key);if (result != null) {return (T) result.get();}T value = valueFromLoader(key, valueLoader);put(key, value);return value;
}

通过打断点的方式可以知道 RedisCache 默认调用的是 lookup(),因此不能应对缓存击穿,如果有相关需求,可以这样配置:@Cacheable(sync = true),开启同步模式,此配置只在 @Cacheable 中才有。

总结

Spring Cache 对于读模式下缓存失效的解决方案:

  • 缓存穿透:cache-null-values: true,允许写入空值
  • 缓存击穿:@Cacheable(sync = true),加锁
  • 缓存雪崩:time-to-live:xxx,设置不同的过期时间

而对于写模式,Spring Cache 并没有相应处理,我们需要使用其它方式处理。


总的来说:

1、对于常规数据(读多写少,及时性、一致性要求不高的数据)完全可以使用 Spring Cache

2、对于特殊数据(比如要求高一致性)则需要特殊处理

相关文章:

Spring Cache的基本使用与分析

概述 使用 Spring Cache 可以极大的简化我们对数据的缓存&#xff0c;并且它封装了多种缓存&#xff0c;本文基于 redis 来说明。 基本使用 1、所需依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-…...

【安全知识】——端口复用隐藏后门

作者名&#xff1a;白昼安全主页面链接&#xff1a; 主页传送门创作初心&#xff1a; 以后赚大钱座右铭&#xff1a; 不要让时代的悲哀成为你的悲哀专研方向&#xff1a; web安全&#xff0c;后渗透技术每日鸡汤&#xff1a; 精彩的人生是在有限的生命中实现无限价值端口复用是…...

Tina_Linux量产测试使用指南_new

OpenRemoved_Tina_Linux_量产测试_使用指南_new 1 概述 文档主要描述如何配置tinatest 并搭建量产测试环境。 1.1 编写目的 • 介绍量产配置方法&#xff1b; • 介绍量产测试环境搭建流程&#xff1b; • 介绍如何使用dragonMAT 软件&#xff1b; • 方便开发人员按照说明…...

STC32单片机 普通 I/O 口中断功能介绍和使用

STC32单片机 普通 I/O 口中断功能和使用✨STC32单片机普通 I/O 口中断&#xff0c;不是传统外部中断. &#x1f516;手册上描述&#xff1a;STC32G 系列支持所有的 I/O 中断&#xff0c;且支持 4 种中断模式&#xff1a;下降沿中断、上升沿中断、低电平中断、高电平中断。每组 …...

计算机学生如何找到第一份实习?

作为一名计算机专业的学生&#xff0c;找到第一份实习是非常重要的一步&#xff0c;它不仅可以帮助你更好地了解行业&#xff0c;增加实践经验&#xff0c;还可以为即将到来的校招提供有力支持。计算机专业的校招&#xff0c;每年都在变得越来越卷。5年前&#xff0c;可能你只要…...

《Python机器学习》基础代码

1&#xff0c;要学习Python机器学习,第一步就是读入数据,这里我们以读入excel的数据为例,利用jupyter notebook来编码,具体教程看这个视频 推荐先上传到jupyter notebook,再用名字.xlsx来导入 Jupyter notebook导入Excel数据的两种方法介绍_哔哩哔哩_bilibili 2&#xff0c;…...

【前端】JS异步加载

文章目录为什么要异步加载如何实现异步加载参考为什么要异步加载 两个原因其实是一个意思。 原因1&#xff1a; JS是单线程的语言&#xff0c;它会同步的执行代码&#xff0c;从上往下执行 但是&#xff0c;一旦网络不好&#xff0c;或要加载的js文件过大的话&#xff0c;会…...

【MySQL】SQL语言的五个部分

DQL 数据查询语言&#xff08;Data Query Language&#xff0c;DQL&#xff09;&#xff1a;DQL主要用于数据的查询&#xff0c;其基本结构是使用SELECT子句&#xff0c;FROM子句和WHERE子句的组合来查询一条或多条数据。 DML 数据操作语言&#xff08;Data Manipulation La…...

详细的IO面试题汇总

IO 流简介 IO 即 Input/Output&#xff0c;输入和输出。数据输入到计算机内存的过程即输入&#xff0c;反之输出到外部存储&#xff08;比如数据库&#xff0c;文件&#xff0c;远程主机&#xff09;的过程即输出。数据传输过程类似于水流&#xff0c;因此称为 IO 流。IO 流在…...

在Linux终端管理你的密码!

大家好&#xff0c;我是良许。 现在是互联网时代&#xff0c;我们每天都要跟各种 APP 、网站打交道&#xff0c;而这些东西基本上都需要注册才可以使用。 但是账号一多&#xff0c;我们自己都经常记不清对应的密码了。有些小伙伴就一把梭&#xff0c;所有的账号密码都是一样。…...

【设计模式】策略模式在Java工程中应用

在之前的文章中&#xff0c;曾经给大家介绍过策略模式&#xff1a;【设计模式】策略模式&#xff0c;在该篇文章中&#xff0c;我们曾很清楚的说到&#xff0c;策略模式主要解决的问题是&#xff1a;在有多种算法相似的情况下&#xff0c;解决使用 if...else 所带来的复杂和难以…...

Linux驱动开发工程师需要掌握哪些技能?

一、前言 Linux驱动开发是一项高度技术性的工作&#xff0c;需要深厚的编程技能和对计算机硬件的深入理解。随着物联网、人工智能等领域的快速发展&#xff0c;Linux驱动开发工程师的需求日益增加。在这篇文章中&#xff0c;我将为您介绍一条Linux驱动开发工程师的学习路线&am…...

【人脸识别】FROM:提升遮挡状态下的人脸识别效果

论文题目&#xff1a;《End2End Occluded Face Recognition by Masking Corrupted Features》 论文地址&#xff1a;https://arxiv.org/pdf/2108.09468v3.pdf 代码地址&#xff1a;https://github.com/haibo-qiu/from 1.前言 人脸识别技术已经取得了显著的进展&#xff0c;主要…...

浏览器缓存

什么是缓存? 当第一次访问网站的时候,比如www.baidu.com,电脑会图片,文件等下载下来,当第二次访问网站的时候,网站就会直接被加载出来. 缓存的好处? 减轻服务器压力,减少请求的放松.提高性能,在本地打开资源肯定比在服务器上获取要快减少宽带的消耗,当我们使用缓存时,只会…...

【软考 系统架构设计师】论文范文③ 论数据访问层设计技术及其应用

>>回到总目录<< 文章目录 论数据访问层设计技术及其应用范文摘要正文论数据访问层设计技术及其应用 在信息系统的开发与建设中,分层设计是一种常见的架构设计方法,区分层次的目的是为了实现“高内聚低耦合”的思想。分层设计能有效简化系统复杂性,使设计结构清…...

802.11 MCS 的最低SNR分析

常常看到这样的表格: 那么这个SNR如何而来? 看看RSSI和SNR的关系,它们之间隔了一个noise floor。从表格看得出,这个底噪在-80~-90之间。 而SNR的核心,也有类似的原因,它和BER有关。...

用于C++的对象关系映射库—YB.ORM

1 介绍YB.ORM YB.ORM 旨在简化与关系数据库交互的 C 应用程序的开发。 对象关系映射器(ORM) 通过将数据库表映射到类并将表行映射到应用程序中的对象来工作&#xff0c;这种方法可能不是对每个数据库应用程序都是最佳的&#xff0c;但它被证明在需要复杂逻辑和事务处理的应用程…...

Cesium 100K数据加载 支持弹窗 动态更改位置

前言&#xff1a;今天总结关于point、label、billboard海量数据加载。后续会研究下大量model加载以及大bim(几百G上T)模型记载 海量点加载 弹窗 加载点位时&#xff0c;不加载弹窗。点击点位时在加载弹窗&#xff0c;及有效的减少加载量&#xff0c;优化性能。 const handler …...

MySQL管理表

在创建表时需要提前了解mysql里面的数据类型 常见的数据类型 创建表 创建表方式1&#xff1a; 格式&#xff1a; CREATE TABLE [IF NOT EXISTS] 表名( 字段1, 数据类型 [约束条件] [默认值], 字段2, 数据类型 [约束条件] [默认值], 字段3, 数据类型 [约束条件] [默认值], ………...

【Java 面试合集】打印一个int整数的32位表示

打印一个int整数的32位表示 1. 概述 嗨&#xff0c;大家好【Java 面试合集】又来了&#xff0c;今天给大家分享的主题是打印一个int整数的32位表示. 2. 32位分析 2.1 为什么是32位呢 不知道看到这篇文章的各位是否都知道&#xff0c;一个int类型的表示方式就是32位呢&#x…...

【WiFi帧结构】

文章目录 帧结构MAC头部管理帧 帧结构 Wi-Fi的帧分为三部分组成&#xff1a;MAC头部frame bodyFCS&#xff0c;其中MAC是固定格式的&#xff0c;frame body是可变长度。 MAC头部有frame control&#xff0c;duration&#xff0c;address1&#xff0c;address2&#xff0c;addre…...

【配置 YOLOX 用于按目录分类的图片数据集】

现在的图标点选越来越多&#xff0c;如何一步解决&#xff0c;采用 YOLOX 目标检测模式则可以轻松解决 要在 YOLOX 中使用按目录分类的图片数据集&#xff08;每个目录代表一个类别&#xff0c;目录下是该类别的所有图片&#xff09;&#xff0c;你需要进行以下配置步骤&#x…...

vue3+vite项目中使用.env文件环境变量方法

vue3vite项目中使用.env文件环境变量方法 .env文件作用命名规则常用的配置项示例使用方法注意事项在vite.config.js文件中读取环境变量方法 .env文件作用 .env 文件用于定义环境变量&#xff0c;这些变量可以在项目中通过 import.meta.env 进行访问。Vite 会自动加载这些环境变…...

Java多线程实现之Thread类深度解析

Java多线程实现之Thread类深度解析 一、多线程基础概念1.1 什么是线程1.2 多线程的优势1.3 Java多线程模型 二、Thread类的基本结构与构造函数2.1 Thread类的继承关系2.2 构造函数 三、创建和启动线程3.1 继承Thread类创建线程3.2 实现Runnable接口创建线程 四、Thread类的核心…...

【JavaSE】多线程基础学习笔记

多线程基础 -线程相关概念 程序&#xff08;Program&#xff09; 是为完成特定任务、用某种语言编写的一组指令的集合简单的说:就是我们写的代码 进程 进程是指运行中的程序&#xff0c;比如我们使用QQ&#xff0c;就启动了一个进程&#xff0c;操作系统就会为该进程分配内存…...

省略号和可变参数模板

本文主要介绍如何展开可变参数的参数包 1.C语言的va_list展开可变参数 #include <iostream> #include <cstdarg>void printNumbers(int count, ...) {// 声明va_list类型的变量va_list args;// 使用va_start将可变参数写入变量argsva_start(args, count);for (in…...

【HarmonyOS 5】鸿蒙中Stage模型与FA模型详解

一、前言 在HarmonyOS 5的应用开发模型中&#xff0c;featureAbility是旧版FA模型&#xff08;Feature Ability&#xff09;的用法&#xff0c;Stage模型已采用全新的应用架构&#xff0c;推荐使用组件化的上下文获取方式&#xff0c;而非依赖featureAbility。 FA大概是API7之…...

leetcode_69.x的平方根

题目如下 &#xff1a; 看到题 &#xff0c;我们最原始的想法就是暴力解决: for(long long i 0;i<INT_MAX;i){if(i*ix){return i;}else if((i*i>x)&&((i-1)*(i-1)<x)){return i-1;}}我们直接开始遍历&#xff0c;我们是整数的平方根&#xff0c;所以我们分两…...

Selenium 查找页面元素的方式

Selenium 查找页面元素的方式 Selenium 提供了多种方法来查找网页中的元素&#xff0c;以下是主要的定位方式&#xff1a; 基本定位方式 通过ID定位 driver.find_element(By.ID, "element_id")通过Name定位 driver.find_element(By.NAME, "element_name"…...

基于Python的气象数据分析及可视化研究

目录 一.&#x1f981;前言二.&#x1f981;开源代码与组件使用情况说明三.&#x1f981;核心功能1. ✅算法设计2. ✅PyEcharts库3. ✅Flask框架4. ✅爬虫5. ✅部署项目 四.&#x1f981;演示效果1. 管理员模块1.1 用户管理 2. 用户模块2.1 登录系统2.2 查看实时数据2.3 查看天…...