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 可以极大的简化我们对数据的缓存,并且它封装了多种缓存,本文基于 redis 来说明。 基本使用 1、所需依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-…...
【安全知识】——端口复用隐藏后门
作者名:白昼安全主页面链接: 主页传送门创作初心: 以后赚大钱座右铭: 不要让时代的悲哀成为你的悲哀专研方向: web安全,后渗透技术每日鸡汤: 精彩的人生是在有限的生命中实现无限价值端口复用是…...
Tina_Linux量产测试使用指南_new
OpenRemoved_Tina_Linux_量产测试_使用指南_new 1 概述 文档主要描述如何配置tinatest 并搭建量产测试环境。 1.1 编写目的 • 介绍量产配置方法; • 介绍量产测试环境搭建流程; • 介绍如何使用dragonMAT 软件; • 方便开发人员按照说明…...
STC32单片机 普通 I/O 口中断功能介绍和使用
STC32单片机 普通 I/O 口中断功能和使用✨STC32单片机普通 I/O 口中断,不是传统外部中断. 🔖手册上描述:STC32G 系列支持所有的 I/O 中断,且支持 4 种中断模式:下降沿中断、上升沿中断、低电平中断、高电平中断。每组 …...
计算机学生如何找到第一份实习?
作为一名计算机专业的学生,找到第一份实习是非常重要的一步,它不仅可以帮助你更好地了解行业,增加实践经验,还可以为即将到来的校招提供有力支持。计算机专业的校招,每年都在变得越来越卷。5年前,可能你只要…...
《Python机器学习》基础代码
1,要学习Python机器学习,第一步就是读入数据,这里我们以读入excel的数据为例,利用jupyter notebook来编码,具体教程看这个视频 推荐先上传到jupyter notebook,再用名字.xlsx来导入 Jupyter notebook导入Excel数据的两种方法介绍_哔哩哔哩_bilibili 2,…...
【前端】JS异步加载
文章目录为什么要异步加载如何实现异步加载参考为什么要异步加载 两个原因其实是一个意思。 原因1: JS是单线程的语言,它会同步的执行代码,从上往下执行 但是,一旦网络不好,或要加载的js文件过大的话,会…...
【MySQL】SQL语言的五个部分
DQL 数据查询语言(Data Query Language,DQL):DQL主要用于数据的查询,其基本结构是使用SELECT子句,FROM子句和WHERE子句的组合来查询一条或多条数据。 DML 数据操作语言(Data Manipulation La…...
详细的IO面试题汇总
IO 流简介 IO 即 Input/Output,输入和输出。数据输入到计算机内存的过程即输入,反之输出到外部存储(比如数据库,文件,远程主机)的过程即输出。数据传输过程类似于水流,因此称为 IO 流。IO 流在…...
在Linux终端管理你的密码!
大家好,我是良许。 现在是互联网时代,我们每天都要跟各种 APP 、网站打交道,而这些东西基本上都需要注册才可以使用。 但是账号一多,我们自己都经常记不清对应的密码了。有些小伙伴就一把梭,所有的账号密码都是一样。…...
【设计模式】策略模式在Java工程中应用
在之前的文章中,曾经给大家介绍过策略模式:【设计模式】策略模式,在该篇文章中,我们曾很清楚的说到,策略模式主要解决的问题是:在有多种算法相似的情况下,解决使用 if...else 所带来的复杂和难以…...
Linux驱动开发工程师需要掌握哪些技能?
一、前言 Linux驱动开发是一项高度技术性的工作,需要深厚的编程技能和对计算机硬件的深入理解。随着物联网、人工智能等领域的快速发展,Linux驱动开发工程师的需求日益增加。在这篇文章中,我将为您介绍一条Linux驱动开发工程师的学习路线&am…...
【人脸识别】FROM:提升遮挡状态下的人脸识别效果
论文题目:《End2End Occluded Face Recognition by Masking Corrupted Features》 论文地址:https://arxiv.org/pdf/2108.09468v3.pdf 代码地址:https://github.com/haibo-qiu/from 1.前言 人脸识别技术已经取得了显著的进展,主要…...
浏览器缓存
什么是缓存? 当第一次访问网站的时候,比如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) 通过将数据库表映射到类并将表行映射到应用程序中的对象来工作,这种方法可能不是对每个数据库应用程序都是最佳的,但它被证明在需要复杂逻辑和事务处理的应用程…...
Cesium 100K数据加载 支持弹窗 动态更改位置
前言:今天总结关于point、label、billboard海量数据加载。后续会研究下大量model加载以及大bim(几百G上T)模型记载 海量点加载 弹窗 加载点位时,不加载弹窗。点击点位时在加载弹窗,及有效的减少加载量,优化性能。 const handler …...
MySQL管理表
在创建表时需要提前了解mysql里面的数据类型 常见的数据类型 创建表 创建表方式1: 格式: CREATE TABLE [IF NOT EXISTS] 表名( 字段1, 数据类型 [约束条件] [默认值], 字段2, 数据类型 [约束条件] [默认值], 字段3, 数据类型 [约束条件] [默认值], ………...
【Java 面试合集】打印一个int整数的32位表示
打印一个int整数的32位表示 1. 概述 嗨,大家好【Java 面试合集】又来了,今天给大家分享的主题是打印一个int整数的32位表示. 2. 32位分析 2.1 为什么是32位呢 不知道看到这篇文章的各位是否都知道,一个int类型的表示方式就是32位呢&#x…...
3.23-3.25笔记
这期实现温湿度采集、光照强度监测、智能设备控制(加湿器、PWM 调光 LED、PWM 调速风扇)确定引脚,根据原理图找出可以使用的引脚开关。根据手册信息PWM口GPIO0_D0和GPIO0_C6,把设备树GPIO0_D0做5G的复位disable,再加入…...
Comsol多重法诺共振拟合:探索与实践
comsol多重法诺共振拟合。 在光学与光子学领域,多重法诺共振现象一直是研究的热点。而Comsol作为一款强大的多物理场仿真软件,为我们研究多重法诺共振提供了有力的工具,尤其是其中的拟合功能,能够帮助我们更精准地理解和分析这一…...
模电小白必看:3种基本放大电路实战对比(附电路图+避坑指南)
模电入门实战:三大基础放大电路深度解析与避坑指南 刚接触模拟电路时,面对共射极、共集极和共基极这三种基本放大电路,很多初学者都会感到困惑——它们看起来相似,但特性却大不相同。本文将用面包板搭建的真实电路和示波器实测波形…...
Qt项目里用dxflib解析CAD图纸,遇到带圆弧的多段线(LWPOLYLINE)怎么画?
Qt项目中利用dxflib解析CAD图纸:带圆弧多段线(LWPOLYLINE)的精确绘制方案 在工业设计、建筑图纸和机械制图领域,DXF文件作为CAD数据交换的标准格式,其精确解析一直是开发者的核心挑战。当使用Qt框架结合dxflib库进行CAD可视化时,优…...
从零到一:在本地CentOS环境完整部署yshop-drink扫码点餐系统的实战指南
1. 环境准备:从零搭建CentOS基础系统 第一次在本地部署yshop-drink扫码点餐系统时,我选择了CentOS 7.9作为基础环境。这个版本既稳定又兼容大多数现代软件包,特别适合作为生产环境使用。建议直接使用阿里云镜像站下载Minimal版本ISO文件&…...
JEECG Boot项目实战:如何优雅地移除登录验证码(前后端完整操作指南)
JEECG Boot项目实战:如何优雅地移除登录验证码(前后端完整操作指南) 在JEECG Boot的开发过程中,验证码功能虽然能有效防止恶意登录,但在某些特定场景下反而会成为效率瓶颈。想象一下这样的场景:开发团队正在…...
超实数(Hyper-reals)的数学革命:从Hewitt到Robinson的探索历程
1. 超实数:一场颠覆传统数学认知的革命 想象一下,当你第一次学习实数时,老师告诉你数轴上的点与实数一一对应,没有任何空隙。这个看似完美的体系在20世纪中叶被一群数学家彻底颠覆了。超实数(Hyper-reals)的…...
OSMnx实战:从OpenStreetMap到GeoPackage,高效构建城市路网分析数据库
1. 为什么选择OSMnx和GeoPackage处理城市路网数据 第一次接触城市路网分析时,我被各种数据格式搞得头大。直到发现OSMnx这个神器,配合GeoPackage格式,工作效率直接翻倍。OSMnx是Python生态中专门处理OpenStreetMap数据的工具包,它…...
Grok-1深度实战指南:3140亿参数混合专家模型的高级部署与优化
Grok-1深度实战指南:3140亿参数混合专家模型的高级部署与优化 【免费下载链接】grok-1 马斯克旗下xAI组织开源的Grok AI项目的代码仓库镜像,此次开源的Grok-1是一个3140亿参数的混合专家模型 项目地址: https://gitcode.com/GitHub_Trending/gr/grok-1…...
华为防火墙NAT映射选择指南:一对一映射 vs 端口映射
华为防火墙NAT映射技术深度解析:一对一映射与端口映射的实战选择 在当今企业网络架构中,如何安全高效地将内部服务暴露给外部访问是一个永恒的技术挑战。华为防火墙提供的NAT映射功能,特别是一对一映射和端口映射两种核心方案,为不…...
