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…...
376. Wiggle Subsequence
376. Wiggle Subsequence 代码 class Solution { public:int wiggleMaxLength(vector<int>& nums) {int n nums.size();int res 1;int prediff 0;int curdiff 0;for(int i 0;i < n-1;i){curdiff nums[i1] - nums[i];if( (prediff > 0 && curdif…...
【android bluetooth 框架分析 04】【bt-framework 层详解 1】【BluetoothProperties介绍】
1. BluetoothProperties介绍 libsysprop/srcs/android/sysprop/BluetoothProperties.sysprop BluetoothProperties.sysprop 是 Android AOSP 中的一种 系统属性定义文件(System Property Definition File),用于声明和管理 Bluetooth 模块相…...
解决本地部署 SmolVLM2 大语言模型运行 flash-attn 报错
出现的问题 安装 flash-attn 会一直卡在 build 那一步或者运行报错 解决办法 是因为你安装的 flash-attn 版本没有对应上,所以报错,到 https://github.com/Dao-AILab/flash-attention/releases 下载对应版本,cu、torch、cp 的版本一定要对…...
【Oracle】分区表
个人主页:Guiat 归属专栏:Oracle 文章目录 1. 分区表基础概述1.1 分区表的概念与优势1.2 分区类型概览1.3 分区表的工作原理 2. 范围分区 (RANGE Partitioning)2.1 基础范围分区2.1.1 按日期范围分区2.1.2 按数值范围分区 2.2 间隔分区 (INTERVAL Partit…...
基于matlab策略迭代和值迭代法的动态规划
经典的基于策略迭代和值迭代法的动态规划matlab代码,实现机器人的最优运输 Dynamic-Programming-master/Environment.pdf , 104724 Dynamic-Programming-master/README.md , 506 Dynamic-Programming-master/generalizedPolicyIteration.m , 1970 Dynamic-Programm…...
以光量子为例,详解量子获取方式
光量子技术获取量子比特可在室温下进行。该方式有望通过与名为硅光子学(silicon photonics)的光波导(optical waveguide)芯片制造技术和光纤等光通信技术相结合来实现量子计算机。量子力学中,光既是波又是粒子。光子本…...
处理vxe-table 表尾数据是单独一个接口,表格tableData数据更新后,需要点击两下,表尾才是正确的
修改bug思路: 分别把 tabledata 和 表尾相关数据 console.log() 发现 更新数据先后顺序不对 settimeout延迟查询表格接口 ——测试可行 升级↑:async await 等接口返回后再开始下一个接口查询 ________________________________________________________…...
接口自动化测试:HttpRunner基础
相关文档 HttpRunner V3.x中文文档 HttpRunner 用户指南 使用HttpRunner 3.x实现接口自动化测试 HttpRunner介绍 HttpRunner 是一个开源的 API 测试工具,支持 HTTP(S)/HTTP2/WebSocket/RPC 等网络协议,涵盖接口测试、性能测试、数字体验监测等测试类型…...
《Offer来了:Java面试核心知识点精讲》大纲
文章目录 一、《Offer来了:Java面试核心知识点精讲》的典型大纲框架Java基础并发编程JVM原理数据库与缓存分布式架构系统设计二、《Offer来了:Java面试核心知识点精讲(原理篇)》技术文章大纲核心主题:Java基础原理与面试高频考点Java虚拟机(JVM)原理Java并发编程原理Jav…...
海云安高敏捷信创白盒SCAP入选《中国网络安全细分领域产品名录》
近日,嘶吼安全产业研究院发布《中国网络安全细分领域产品名录》,海云安高敏捷信创白盒(SCAP)成功入选软件供应链安全领域产品名录。 在数字化转型加速的今天,网络安全已成为企业生存与发展的核心基石,为了解…...
