Springboot 内置缓存与整合Redis作为缓存

Spring Boot 的缓存注解允许开发者在不修改业务逻辑的情况下,将方法的计算结果缓存起来,从而减少重复计算和数据库查询,提高系统性能。

 1、Spring Boot Cache 的基本用法及常用注解

1. 引入依赖

首先,需要在项目中引入缓存相关依赖。

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

2. 启用缓存

在 Spring Boot 主程序类上添加 @EnableCaching 注解,开启缓存支持:

@SpringBootApplication
@EnableCaching
public class CacheApplication {public static void main(String[] args) {SpringApplication.run(CacheApplication.class, args);}
}

3. 常用注解

@Cacheable
  • 用于将方法的返回结果缓存起来。
  • 方法被调用时,Spring 会先检查缓存中是否有数据,如果有则直接返回缓存结果,否则执行方法并将结果放入缓存。
  • @Cacheable 本身并不直接提供过期时间的配置。缓存的过期时间取决于具体的缓存提供者。
@Service
public class UserService {@Cacheable(value = "userCache", key = "#id")#根据id不同查找缓存,在同一个缓存空间(如 responseCache)内,可以存储多个结果,每个结果与唯一的缓存键对应(即不同的请求参数对应不同的缓存结果)。public User getUserById(Long id) {// 假设这是一个耗时的数据库查询return userRepository.findById(id).orElse(null);}
}

注:

  • @Cacheable:表示该方法的结果应该被缓存。Spring 在方法第一次被调用时会执行该方法并缓存其结果,后续对同一参数的调用将直接返回缓存中的结果。

  • value = "userCache":指定缓存的名称,value 属性对应缓存的命名空间。这里的 userCache 是缓存的名称,用于存储此方法的返回结果。userCache 可以对应一个具体的缓存实现(如 Redis、EhCache 等)中一个独立的缓存区域。

  • key = "#id":指定缓存的键。使用 Spring 表达式语言(SpEL)来定义缓存键的生成规则,#id 表示方法参数 id 的值作为缓存的键。

    • 在这里,#id 会直接使用方法参数 id 的值。例如,当 id=1 时,缓存键就是 1
    • 如果不指定 key 属性,Spring 会默认将所有方法参数的组合作为缓存键。

默认键生成机制

@Cacheable 注解没有指定 key 时,Spring Cache 会将所有方法参数的组合作为默认缓存键。具体来说,Spring Cache 使用 SimpleKeyGenerator 生成缓存键:

  1. 单一参数:如果方法有一个参数,且未指定 key,Spring 会直接使用该参数作为缓存键。
  2. 多参数:如果方法有多个参数,Spring 会将它们组合成一个 SimpleKey 对象作为缓存键。
  3. 无参数:如果方法没有参数,Spring 会使用 SimpleKey.EMPTY 作为缓存键。

如果传入的是自定义对象参数,Spring 会调用该对象的 hashCodeequals 方法来识别不同参数值的唯一性,以确保生成的缓存键唯一。对于自定义对象,如果没有重写 equalshashCode 方法,则默认使用 Object 类的实现。ObjecthashCodeequals 方法基于对象的内存地址判断两个对象是否相等,这样不同实例即使内容相同,也会被认为是不同的对象。因此,不重写 equalshashCode 可能会导致缓存命中失败,从而产生重复的缓存条目。

  • 不指定 key 且传入自定义对象:需要重写对象的 equalshashCode 方法,以确保相同内容的对象具有相同的缓存键。
  • 推荐方式:如果传入对象属性确定,可以使用 SpEL 表达式明确指定缓存键(如 key = "#user.id"),这样更简洁并避免了对 equalshashCode 的依赖。
@CachePut
  • 用于强制更新缓存内容,方法每次都会执行,将返回值放入缓存。
  • 常用于方法更新数据后,同时更新缓存中的数据。
    
    @Service
    public class UserService {@CachePut(value = "userCache", key = "#user.id")public User updateUser(User user) {// 更新数据库中的用户信息return userRepository.save(user);}
    }
    

    @CachePut 注解表示方法执行完成后将结果更新到 userCache 中,key 为 user.id

@CacheEvict
  • 用于清除缓存数据。
  • 通常用于删除或更新方法,用于从缓存中移除不再需要的数据。
    @Service
    public class UserService {@CacheEvict(value = "userCache", key = "#id")public void deleteUser(Long id) {// 删除数据库中的用户userRepository.deleteById(id);}
    }

    @CacheEvict 会将缓存 userCache 中 key 为 id 的缓存项删除,确保缓存中的数据与数据库保持一致。

@Caching
  • 用于组合多个缓存注解,适用于需要同时执行多个缓存操作的场景。

@Service
public class UserService {@Caching(put = { @CachePut(value = "userCache", key = "#user.id") },evict = { @CacheEvict(value = "userListCache", allEntries = true) })public User saveUser(User user) {// 保存用户信息return userRepository.save(user);}
}

在此示例中,@Caching 组合了 @CachePut@CacheEvict,即在缓存 userCache 中更新用户数据,同时清除 userListCache 中的所有缓存项。

4. 自定义缓存键和条件

Spring Boot Cache 允许通过 keycondition 参数自定义缓存键和条件。

  • key:自定义缓存的 key,可以使用 SpEL 表达式。默认是方法参数的组合。
  • condition:满足指定条件时才缓存,使用 SpEL 表达式。
  • unless:满足条件时不缓存,优先级高于 condition
@Cacheable(value = "userCache", key = "#user.id", condition = "#user.age > 18", unless = "#result == null")
public User getUser(User user) {return userRepository.findById(user.getId()).orElse(null);
}

 在此例中,condition 表示只有用户年龄大于 18 时才缓存,unless 表示当方法返回值为 null 时不缓存。

5.完整示例

@Service
public class UserService {@Cacheable(value = "userCache", key = "#id")public Optional<User> getUserById(Long id) {// 模拟数据库查询return userRepository.findById(id);}@CachePut(value = "userCache", key = "#user.id")public User updateUser(User user) {// 更新数据库中的用户信息return userRepository.save(user);}@CacheEvict(value = "userCache", key = "#id")public void deleteUser(Long id) {// 从数据库中删除用户信息userRepository.deleteById(id);}
}

缺点:本地缓存, 分布式场景容易产生数据不一致的情况。

2、Spring Boot 结合 Redis 实现缓存

为了解决缓存一致问题,可以引入分布式缓存Redis。

1. 引入依赖

项目中添加 Redis 的依赖:

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

2. 配置 Redis 连接

application.ymlapplication.properties 中配置 Redis 连接信息:

# Spring Cache 配置
spring.cache.type=redis   # 设置 Spring 缓存使用 Redis# Redis 连接配置
spring.redis.host=localhost   # Redis 服务器地址
spring.redis.port=6379        # Redis 服务器端口
spring.redis.password=yourpassword   # Redis 连接密码,如果没有则省略
# Redis 缓存过期时间(可选)
spring.cache.redis.time-to-live=60000   # 设置缓存的默认过期时间(单位为毫秒),此处为 60 秒spring.cache.redis.use-key-prefix=true    # 使用 key 前缀,果有多种业务数据存储在同一个 Redis 实例中,建议开启 key 前缀
spring.cache.redis.key-prefix=test_cache_  # 设置 Redis 缓存的 key 前缀

3. 启用缓存支持

同上

4. 使用缓存注解 

同上

这样即可使用 Redis分布式缓存替换Spring Boot 自带缓存显著提升性能,解决分布式场景下数据不一致问题。

3、引入缓存带来的问题

缓存击穿

定义

缓存击穿是指一个热点数据在缓存过期的瞬间,大量并发请求访问该数据,由于缓存刚好过期,导致请求同时涌入数据库查询。这个问题会导致数据库压力骤增,甚至崩溃。

原因
  • 热点数据在缓存失效的瞬间,大量请求同时访问该数据。
  • 高并发场景下,单一热点数据的缓存失效后数据库压力过大。
解决方案
  1. 设置热点数据永不过期(逻辑过期):对于少量非常热门的数据,可以设置缓存永不过期。然后通过后台异步线程来定时更新缓存,避免缓存失效导致的瞬间压力增大。
  2. 加锁机制:在缓存失效时,只有一个线程去数据库中查询数据并回填缓存,其他线程等待第一个线程完成后从缓存读取。可以使用分布式锁(如 Redis 分布式锁)来控制并发。
  3. 双重检查:在缓存失效时再进行二次检查。在缓存过期的情况下,多个线程查询缓存后都会去请求数据库,可以在第一次查询数据库后立即更新缓存,再次检查缓存以减少数据库的并发压力。
  4. 增加定时任务定期刷新缓存:通过 Spring 的定时任务来实现定时刷新缓存,保证热点数据在缓存即将失效时被重新加载。

缓存穿透

定义

缓存穿透是指大量请求查询缓存中不存在的数据,导致请求直接穿透缓存到数据库,给数据库带来极大压力。例如,用户查询一个不存在的用户 ID,由于缓存中没有该数据且数据库也没有结果,每次查询都绕过缓存直接访问数据库。

原因
  • 查询的 key 不存在,缓存没有数据,直接查询数据库。
  • 恶意攻击或程序错误导致频繁查询不存在的 key。
解决方案
  1. 缓存空结果:对于数据库查询结果为空的数据,将空结果也缓存一段时间(例如 5 分钟)。这样,短时间内相同的请求不会频繁查询数据库。可以通过设置较短的过期时间来避免大量无效数据长期占用缓存。(spring.cache.redis.cache-null-values=true)
  2. 布隆过滤器:在缓存之前增加一个布隆过滤器,用于判断 key 是否可能存在。布隆过滤器可以有效过滤掉不存在的数据,避免直接查询数据库。
  3. 参数校验:对用户输入的 key 进行校验,防止恶意请求。比如查询数据库前对 key 做基础检查,确保格式和范围有效。

缓存雪崩

定义

缓存雪崩是指缓存中大量数据在同一时间失效,导致大量请求同时打到数据库,造成数据库压力激增。缓存雪崩可能会导致系统出现短暂或持续的不可用。

原因
  • 大量缓存设置了相同的过期时间,在某一时刻同时失效。
  • 系统重启或崩溃,导致所有缓存失效。
解决方案
  1. 缓存过期时间加随机:避免所有缓存设置相同的过期时间,可以在过期时间上增加一个随机值,使得缓存过期时间分散,避免集中失效。
  2. 缓存预热:在系统启动时,将常用的热点数据提前加载到缓存中,避免高峰时段突然访问数据库。
  3. 分级降级策略:在缓存雪崩发生时,可以使用限流策略和降级策略,限制数据库的访问频率。同时,也可以用备用缓存来缓解瞬时压力。
  4. 多层缓存架构:使用多级缓存(如本地缓存 + 分布式缓存)或多机房缓存,实现分布式缓存冗余,避免单点失效导致大量缓存失效。

总结:

问题定义解决方案
缓存穿透请求大量不存在的 key,导致直接查询数据库缓存空结果、布隆过滤器、参数校验
缓存击穿热点数据过期,瞬时大量请求穿透缓存,打到数据库设置热点数据永不过期、加锁机制、双重检查
缓存雪崩缓存中大量数据同时失效,导致数据库请求激增设置过期时间加随机、缓存预热、分级降级策略、多层缓存

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

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

相关文章

《西部皮革》是什么级别的期刊?是正规期刊吗?能评职称吗?

​问题解答 问&#xff1a;《西部皮革》是不是核心期刊&#xff1f; 答&#xff1a;不是&#xff0c;是知网收录的正规学术期刊。 问&#xff1a;《西部皮革》级别&#xff1f; 答&#xff1a;省级。主管单位&#xff1a;四川省经济和信息化厅 …

【4】函数与结构体

文章目录 一、函数的基本流程及调用二、包的使用原理三、函数的使用注意事项四、defer的使用五、字符串常用系统函数六、时间函数七、常用内置函数八、错误处理机制及自定义错误 一、函数的基本流程及调用 package mainimport ("fmt""strings" )// 定义简…

供应SW1108P集成氮化镓直驱的高频准谐振IC

1. 概述 SW1108P 是一款针对离线式反激变换器的高性能高集成度准谐振电流模式 PWM 控制器。 SW1108P 内置 6V 的驱动电压&#xff0c;可直接用于驱动氮化镓功率管&#xff1b;芯片工作于带谷底锁定功能 的谷底开启模式&#xff0c;同时集成频率抖动功能以优化 EMI 性能&…

uniapp使用中小问题及解决方法集合

1、 u-input 标签 设置只读、禁用后,click事件不生效 // 解决u-input 标签 设置只读、禁用后,click事件不生效&#xff08;不弹出弹框&#xff09; .input-disabled-click {pointer-events: none; }2、 uniapp实现u-datetime-picker时间选择器的默认日期定位&#xff0c;解决d…

HTML 基础标签——表格标签<table>

文章目录 1. `<table>` 标签:定义表格2. `<tr>` 标签:定义表格行3. `<th>` 标签:定义表头单元格4. `<td>` 标签:定义表格单元格5. `<caption>` 标签:为表格添加标题6. `<thead>` 标签:定义表格头部7. `<tbody>` 标签:定义表格…

使用Nginx作为反向代理和负载均衡器

&#x1f493; 博客主页&#xff1a;瑕疵的CSDN主页 &#x1f4dd; Gitee主页&#xff1a;瑕疵的gitee主页 ⏩ 文章专栏&#xff1a;《热点资讯》 使用Nginx作为反向代理和负载均衡器 引言 Nginx 简介 安装 Nginx Ubuntu CentOS 配置 Nginx 作为反向代理 配置 Nginx 作为负载…

「实战应用」使用 DHTMLX 构建数据透视表,促进有效的数据分析

概述&#xff1a;在本文中&#xff0c;您将了解组织何时选择数据透视表来处理大数据&#xff0c;并熟悉用于在网页上实现此功能的 DHTMLX 工具。 如今&#xff0c;高效处理大数据已成为企业的必需。企业每天必须处理大量数据&#xff0c;以将其转化为可操作的见解并获得竞争优…

Stable diffusion 3.5本地运行环境配置记录

1.环境配置 创建虚环境 conda create -n sd3.5 python3.10Pytorch(>2.0) conda install pytorch2.2.2 torchvision0.17.2 torchaudio2.2.2 pytorch-cuda12.1 -c pytorch -c nvidiaJupyter能使用Anaconda虚环境 conda install ipykernel python -m ipykernel install --user …

第 十 章 积极性,培训以及经验(程序员开发心理学)

1&#xff09;无论我们如何精心地为学习建立一个最佳的物理环境&#xff0c;如果不懂如何利用所有可能的信息来帮助学习&#xff0c;再好的环境也不可能保证手们能够成功地完成学习任务 2&#xff09;为了能够对信息的这种损失有所认识&#xff0c;请看这样一个例子 - 在一次测…

openGauss数据库-头歌实验1-4 数据库及表的创建

一、创建数据库 &#xff08;一&#xff09;任务描述 本关任务&#xff1a;创建指定数据库。 &#xff08;二&#xff09;相关知识 数据库其实就是可以存放大量数据的仓库&#xff0c;学习数据库我们就从创建一个数据库开始吧。 为了完成本关任务&#xff0c;你需要掌握&a…

(自用复习题)常微分方程08

题目来源 常微分方程(第四版) (王高雄,周之铭,朱思铭,王寿松) 高等教育出版社 书中习题4.1 对应知识 非齐次线性微分方程 3.已知齐次线性微分方程的基本解组 x 1 , x 2 x_1,x_2 x1​,x2​&#xff0c;求下列方程对应的非齐次线性微分方程的通解 三道题都是常数变易法 (1)…

CSRF初级靶场

靶场 针对DVWA么有防御 源码&#xff1a; <?phpif( isset( $_GET[ Change ] ) ) {// Get input$pass_new $_GET[ password_new ];$pass_conf $_GET[ password_conf ];// Do the passwords match?if( $pass_new $pass_conf ) {// They do!$pass_new ((isset($GLOBA…

图解TCP三次握手:一步步构建网络会话

在互联网通信中&#xff0c;确保数据传输的可靠性至关重要。TCP三次握手的过程正是为了解决这一问题而设计的。在建立连接之前&#xff0c;客户端和服务器需要确认彼此的存在与准备状态&#xff0c;以防止因网络延迟或数据丢失而导致的错误。通过三次握手&#xff0c;双方不仅能…

[ shell 脚本实战篇 ] 编写恶意程序实现需求(恶意程序A监测特定目录B出现特定文件C执行恶意操作D-linux)

&#x1f36c; 博主介绍 &#x1f468;‍&#x1f393; 博主介绍&#xff1a;大家好&#xff0c;我是 _PowerShell &#xff0c;很高兴认识大家~ ✨主攻领域&#xff1a;【渗透领域】【数据通信】 【通讯安全】 【web安全】【面试分析】 &#x1f389;点赞➕评论➕收藏 养成习…

讲讲RabbitMQ 性能优化

大家好&#xff0c;我是锋哥。今天分享关于【RabbitMQ 性能优化&#xff1f;】面试题。希望对大家有帮助&#xff1b; 讲讲RabbitMQ 性能优化 1000道 互联网大厂Java工程师 精选面试题-Java资源分享网 RabbitMQ 是一个强大的消息代理&#xff0c;广泛用于分布式系统中&#x…

2-139 基于matlab的弹道轨迹仿真

基于matlab的弹道轨迹仿真。设计GUI图形用户界面&#xff0c;对导弹参数根据需求进行设置&#xff0c;直观的实现更改攻角、各级火箭喷射时间等参数后得到对应参数下的导弹弹道图像以及导弹的飞行时间和飞行距离。得到飞行时间集导弹射程。程序已调通&#xff0c;可直接运行。 …

【spark的集群模式搭建】Standalone集群模式的搭建(简单明了的安装教程)

文章目录 1、使用Anaconda部署Python2、上传、解压、重命名3、创建软连接4、配置spark环境变量5、修改 spark-env.sh配置文件6、启动hdfs&#xff0c;创建文件夹7、修改spark-defaults.conf配置文件8、修改workers配置文件9、修改log4j.properties配置文件&#xff08;可选&…

AI 编译器学习笔记之十 -- 基于atc工具进行onnx到om转换

1、input_shape 获取&#xff1f; atc --modelmodelTTS5_32.onnx --framework5 --outputmodelTTS5_32 --soc_versionAscend910B4 --input_shape"x:1,-1;x_lengths:1;sid:1;tone:1,-1;language:1,-1;bert:1,1024,-1;ja_bert:1,768,-1" --precision_mode_v2origin a)…

HTML 基础标签——多媒体标签<img>、<object> 与 <embed>

文章目录 1. `<img>` 标签主要属性示例注意事项2. `<object>` 标签概述主要属性示例注意事项3. `<embed>` 标签概述主要属性示例注意事项小结在现代网页设计中,多媒体内容的使用变得越来越重要,因为它能够有效增强用户体验、吸引注意力并传达信息。HTML 提…

Apache 负载均衡详细配置步骤

一、引言 在当今的互联网时代&#xff0c;随着业务的不断增长和用户量的增加&#xff0c;单一服务器往往难以满足高并发的请求。为了提高系统的可用性、可靠性和性能&#xff0c;负载均衡技术应运而生。Apache HTTP Server&#xff08;以下简称 Apache&#xff09;作为一款广泛…