掌握 Spring Boot 中的缓存:技术和最佳实践
缓存是一种用于将经常访问的数据临时存储在更快的存储层(通常在内存中)中的技术,以便可以更快地满足未来对该数据的请求,从而提高应用程序的性能和效率。在 Spring Boot 中,缓存是一种简单而强大的方法,可以通过减少数据库命中、API 调用或昂贵的计算来增强应用程序性能。

为什么要使用缓存?
- 改进的性能:缓存通过从更快的缓存中提供频繁请求的数据而不是重新计算或重新获取数据来减少响应时间。
- 减少资源负载:减少数据库或外部服务等底层资源的负载。
- 成本效率:当您的应用程序在云中运行或使用第三方服务时,减少 API 调用或数据库访问次数可以节省成本。
- 更好的可扩展性:通过缓存,您可以通过降低后端服务的压力来允许应用程序处理更多并发请求。

Spring Boot中的缓存
Spring Boot 使用@Cacheable 、 @CachePut和@CacheEvict注释等提供了一个用于缓存的抽象层。这种抽象允许您轻松集成不同的缓存实现(例如 EhCache、Hazelcast、Redis 等)。
Spring Boot 缓存中的关键概念
- 缓存存储:这是数据缓存的实际位置(内存中、Redis、EhCache 等)。
- 缓存键:用于存储和检索缓存数据的标识符。
- 缓存值:与缓存键关联的实际数据。
- 缓存管理器:用于管理不同缓存实现的 Spring 抽象。
缓存操作:
@Cacheable:缓存方法的结果。@CachePut:更新缓存而不影响方法的执行。@CacheEvict:从缓存中删除条目。
2.2. Spring Boot 缓存注解
@EnableCaching :此注释启用 Spring Boot 中的缓存支持。
- 要启用缓存,您只需使用
@EnableCaching注释您的主配置类。
@SpringBootApplication
@EnableCaching
public class Application {public static void main(String[] args) {SpringApplication.run(Application.class, args);}
}
@Cacheable :该注解用于缓存方法调用的结果。当调用@Cacheable注解的方法时,Spring会检查结果是否已经在缓存中。如果是,则返回缓存的值;否则,执行该方法,并将结果存储在缓存中。
@Cacheable("employees")
public Employee getEmployeeById(Long id) {// Simulate expensive operationreturn employeeRepository.findById(id).orElse(null);
}
@CacheEvict :这用于从缓存中删除条目。您可以指定要逐出哪个键或缓存。
@CacheEvict(value = "employees", allEntries = true)
public void clearCache() {// Clears all cache entries for 'employees'
}
@CachePut :与@Cacheable不同,此注释确保方法始终执行,但用结果更新缓存。
@CachePut(value = "employees", key = "#employee.id")
public Employee updateEmployee(Employee employee) {return employeeRepository.save(employee);
}
缓存机制工作流程
步骤1 :向带有@Cacheable注释的方法发出请求。
步骤 2 :Spring 检查缓存中的数据是否可用:
- 如果是,则返回缓存的值而不执行该方法。
- 如果没有,则执行该方法,缓存结果,然后返回结果。
步骤3 :对于@CachePut ,执行该方法,并且无论key是否已经存在于缓存中,结果都会被缓存。
步骤4 :对于@CacheEvict ,Spring根据提供的缓存键删除缓存条目(或清除整个缓存)。
在 Spring Boot 中配置缓存存储
Spring Boot 支持多个缓存提供程序,例如:
- ConcurrentMapCache (默认,内存缓存)
- EhCache 高速缓存
- Hazelcast 榛卡斯特
- Redis 雷迪斯
- Caffeine 咖啡因
生产场景用到的缓存中间件

如何在生产中应用
- 由于其性能、集群功能、灵活性和广泛的功能, Redis通常是大多数生产环境的最佳缓存提供程序。
- 如果您正在使用分布式系统或微服务,Redis 或Hazelcast因其可扩展性而更适合。
- 对于易于集成和本地缓存就足够的小型单节点应用程序, EhCache或Caffeine会更易于使用。
为了演示在带有 MySQL 的 Spring Boot 应用程序中使用EhCache 的完整示例,我们将构建一个基本应用程序,该应用程序对
Employee实体执行 CRUD 操作,并利用缓存来获取、更新和删除操作。
设置项目
We’ll use the following: 我们将使用以下内容:
- 用于数据库交互的Spring Boot Starter Data JPA 。
- EhCache作为缓存提供者。
- MySQL作为数据库。
依赖关系
在您的pom.xml中,包含必要的依赖项:
<dependencies><!-- Spring Boot Starter Data JPA --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-jpa</artifactId></dependency><!-- Spring Boot Starter Cache --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-cache</artifactId></dependency><!-- EhCache --><dependency><groupId>org.ehcache</groupId><artifactId>ehcache</artifactId></dependency><!-- MySQL Driver --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><scope>runtime</scope></dependency><!-- Spring Boot Starter Web --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!-- Lombok (for boilerplate code) --><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><scope>provided</scope></dependency>
</dependencies>
EhCache配置
在src/main/resources目录下创建**ehcache.xml**文件:
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd"><cache name="employees"maxEntriesLocalHeap="1000"timeToLiveSeconds="3600"memoryStoreEvictionPolicy="LRU"></cache>
</ehcache>
应用程序属性
在application.properties中,配置 MySQL 并启用 EhCache:
# MySQL Configuration
spring.datasource.url=jdbc:mysql://localhost:3306/employee_db
spring.datasource.username=root
spring.datasource.password=yourpassword
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true# EhCache Configuration
spring.cache.type=ehcache
spring.cache.ehcache.config=classpath:ehcache.xml
实体类
定义Employee实体类:
package com.example.caching.entity;import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;import javax.persistence.*;@Entity
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Employee {@Id@GeneratedValue(strategy = GenerationType.IDENTITY)private Long id;private String name;private String department;private double salary;
}
存储库接口
创建一个扩展JpaRepository EmployeeRepository接口:
package com.example.caching.repository;import com.example.caching.entity.Employee;
import org.springframework.data.jpa.repository.JpaRepository;public interface EmployeeRepository extends JpaRepository<Employee, Long> {
}
服务层
在EmployeeService中实现缓存逻辑:
package com.example.caching.service;import com.example.caching.entity.Employee;
import com.example.caching.repository.EmployeeRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;import java.util.Optional;@Service
public class EmployeeService {@Autowiredprivate EmployeeRepository employeeRepository;// Fetch employee and cache the result@Cacheable(value = "employees", key = "#id")public Employee getEmployeeById(Long id) {System.out.println("Fetching from database...");Optional<Employee> employee = employeeRepository.findById(id);return employee.orElse(null);}// Update employee and update cache@CachePut(value = "employees", key = "#employee.id")public Employee updateEmployee(Employee employee) {System.out.println("Updating employee in database and cache...");return employeeRepository.save(employee);}// Delete employee and evict cache@CacheEvict(value = "employees", key = "#id")public void deleteEmployee(Long id) {System.out.println("Deleting employee from database and evicting cache...");employeeRepository.deleteById(id);}// Clear entire cache for 'employees'@CacheEvict(value = "employees", allEntries = true)public void clearCache() {System.out.println("Cache cleared!");}
}
控制器层
创建一个 REST 控制器来公开 CRUD 端点:
package com.example.caching.controller;import com.example.caching.entity.Employee;
import com.example.caching.service.EmployeeService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;@RestController
@RequestMapping("/api/employees")
public class EmployeeController {@Autowiredprivate EmployeeService employeeService;// Fetch employee by ID@GetMapping("/{id}")public Employee getEmployee(@PathVariable Long id) {return employeeService.getEmployeeById(id);}// Update employee@PutMapping("/{id}")public Employee updateEmployee(@PathVariable Long id, @RequestBody Employee employee) {employee.setId(id);return employeeService.updateEmployee(employee);}// Delete employee@DeleteMapping("/{id}")public void deleteEmployee(@PathVariable Long id) {employeeService.deleteEmployee(id);}// Clear cache@DeleteMapping("/cache/clear")public void clearCache() {employeeService.clearCache();}
}
主要应用类
通过添加@EnableCaching在 Spring Boot 应用程序中启用缓存:
package com.example.caching;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.annotation.EnableCaching;@SpringBootApplication
@EnableCaching
public class CachingApplication {public static void main(String[] args) {SpringApplication.run(CachingApplication.class, args);}
}
测试应用程序
启动应用程序并使用 Postman(或类似工具)来访问以下端点:
获取员工(缓存结果):
GET http://localhost:8080/api/employees/{id}
第一个请求将从数据库中获取员工并缓存结果。后续对同一员工 ID 的请求将从缓存中返回结果。
更新员工(更新缓存):
PUT http://localhost:8080/api/employees/{id}
更新数据库和缓存中的员工。
删除员工(删除缓存):
DELETE http://localhost:8080/api/employees/{id}
从数据库中删除员工并删除缓存条目。
Clear Cache: 清空缓存:
DELETE http://localhost:8080/api/employees/cache/clear
清除employees的所有缓存条目。
这个完整的 Spring Boot 示例演示了如何将EhCache与 MySQL 数据库集成以缓存 CRUD 操作。 @Cacheable 、 @CachePut和@CacheEvict注释无缝处理缓存,通过减少数据库负载来提高性能。
相关文章:
掌握 Spring Boot 中的缓存:技术和最佳实践
缓存是一种用于将经常访问的数据临时存储在更快的存储层(通常在内存中)中的技术,以便可以更快地满足未来对该数据的请求,从而提高应用程序的性能和效率。在 Spring Boot 中,缓存是一种简单而强大的方法,可以…...
动手学深度学习10.5. 多头注意力-笔记练习(PyTorch)
本节课程地址:多头注意力代码_哔哩哔哩_bilibili 本节教材地址:10.5. 多头注意力 — 动手学深度学习 2.0.0 documentation 本节开源代码:...>d2l-zh>pytorch>chapter_multilayer-perceptrons>multihead-attention.ipynb 多头注…...
13 设计模式之外观模式(家庭影院案例)
一、什么是外观模式? 1.定义 在日常生活中,许多人喜欢通过遥控器来控制家中的电视、音响、DVD 播放器等设备。虽然这些设备各自独立工作,但遥控器提供了一个简洁的界面,让用户可以轻松地操作多个设备。而这一设计理念正是 外观模…...
单片机学习笔记 12. 定时/计数器_定时
更多单片机学习笔记:单片机学习笔记 1. 点亮一个LED灯单片机学习笔记 2. LED灯闪烁单片机学习笔记 3. LED灯流水灯单片机学习笔记 4. 蜂鸣器滴~滴~滴~单片机学习笔记 5. 数码管静态显示单片机学习笔记 6. 数码管动态显示单片机学习笔记 7. 独立键盘单片机学习笔记 8…...
Web安全基础实践
实践目标 (1)理解常用网络攻击技术的基本原理。(2)Webgoat实践下相关实验。 WebGoat WebGoat是由著名的OWASP负责维护的一个漏洞百出的J2EE Web应用程序,这些漏洞并非程序中的bug,而是故意设计用来讲授We…...
Zookeeper集群数据是如何同步的?
大家好,我是锋哥。今天分享关于【Zookeeper集群数据是如何同步的?】面试题。希望对大家有帮助; Zookeeper集群数据是如何同步的? 1000道 互联网大厂Java工程师 精选面试题-Java资源分享网 Zookeeper集群中的数据同步是通过一种称为ZAB(Zo…...
SpringCloud框架学习(第六部分:Sentinel实现熔断与限流)
目录 十四、SpringCloud Alibaba Sentinel实现熔断与限流 1.简介 2.作用 3.下载安装 4.微服务 8401 整合 Sentinel 入门案例 5.流控规则 (1)基本介绍 (2)流控模式 Ⅰ. 直接 Ⅱ. 关联 Ⅲ. 链路 (3࿰…...
动态规划-----路径问题
动态规划-----路径问题 下降最小路径和1:状态表示2:状态转移方程3 初始化4 填表顺序5 返回值6 代码实现 总结: 下降最小路径和 1:状态表示 假设:用dp[i][j]表示:到达[i,j]的最小路径 2:状态转…...
Rust循环引用与多线程并发
循环引用与自引用 循环引用的概念 循环引用指的是两个或多个对象之间相互持有对方的引用。在 Rust 中,由于所有权和生命周期的严格约束,直接创建循环引用通常会导致编译失败。例如: // 错误的循环引用示例 struct Node {next: Option<B…...
东方隐侠网安瞭望台第8期
谷歌应用商店贷款应用中的 SpyLoan 恶意软件影响 800 万安卓用户 迈克菲实验室的新研究发现,谷歌应用商店中有十多个恶意安卓应用被下载量总计超过 800 万次,这些应用包含名为 SpyLoan 的恶意软件。安全研究员费尔南多・鲁伊斯上周发布的分析报告称&…...
底部导航栏新增功能按键
场景需求: 在底部导航栏添加power案件,单击息屏,长按 关机 如下实现图 借此需求,需要掌握技能: 底部导航栏如何实现新增、修改、删除底部导航栏流程对底部导航栏部分样式如何修改。 比如放不下、顺序排列、坑点如…...
C++ 之弦上舞:string 类与多样字符串操作的优雅旋律
string 类的重要性及与 C 语言字符串对比 在 C 语言中,字符串是以 \0 结尾的字符集合,操作字符串需借助 C 标准库的 str 系列函数,但这些函数与字符串分离,不符合 OOP 思想,且底层空间管理易出错。而在 C 中࿰…...
centos8:Could not resolve host: mirrorlist.centos.org
【1】错误消息: [rootcentos211 redis-7.0.15]# yum update CentOS Stream 8 - AppStream …...
Linux 定时任务 命令解释 定时任务格式详解
目录 时间命令 修改时间和日期 定时任务格式 定时任务执行 查看定时任务进程 重启定时任务 时间命令 #查看时间 [rootlocalhost ~]# date 2021年 07月 23日 星期五 14:38:19 CST --------------------------------------- [rootlocalhost ~]# date %F 2021-07-23 -----…...
aws(学习笔记第十五课) 如何从灾难中恢复(recover)
aws(学习笔记第十五课) 如何从灾难中恢复 学习内容: 使用CloudWatch对服务器进行监视与恢复区域(region),可用区(available zone)和子网(subnet)使用自动扩展(AutoScalingGroup) 1. 使用CloudWatch对服务器进行监视与恢复 整体架构 这里模拟Jenkins Se…...
github webhooks 实现网站自动更新
本文目录 Github Webhooks 介绍Webhooks 工作原理配置与验证应用云服务器通过 Webhook 自动部署网站实现复制私钥编写 webhook 接口Github 仓库配置 webhook以服务的形式运行 app.py Github Webhooks 介绍 Webhooks是GitHub提供的一种通知方式,当GitHub上发生特定事…...
【C语言】递归的内存占用过程
递归 递归是函数调用自身的一种编程技术。在C语言中,递归的实现会占用内存栈(Call Stack),每次递归调用都会在栈上分配一个新的 “栈帧(Stack Frame)”,用于存储本次调用的函数局部变量、返回地…...
365天深度学习训练营-第P6周:VGG-16算法-Pytorch实现人脸识别
🍨 本文为🔗365天深度学习训练营中的学习记录博客🍖 原作者:K同学啊 文为「365天深度学习训练营」内部文章 参考本文所写记录性文章,请在文章开头带上「👉声明」 🍺要求: 保存训练过…...
企业AI助理在数据分析与决策中扮演的角色
在当今这个数据驱动的时代,企业每天都需要处理和分析大量的数据,以支持其业务决策。然而,面对如此庞大的数据量,传统的数据分析方法已经显得力不从心。幸运的是,随着人工智能(AI)技术的不断发展…...
洛谷 B2029:大象喝水 ← 圆柱体体积
【题目来源】https://www.luogu.com.cn/problem/B2029【题目描述】 一只大象口渴了,要喝 20 升水才能解渴,但现在只有一个深 h 厘米,底面半径为 r 厘米的小圆桶 (h 和 r 都是整数)。问大象至少要喝多少桶水才会解渴。 …...
嵌入式系统架构和微处理器深入分析和总结
嵌入式系统架构和微处理器深入分析与总结 嵌入式系统的核心是架构与微处理器的有机结合。架构定义了系统的“思维方式和规则”,而微处理器则是执行这些规则的“物理引擎”。 第一部分:嵌入式系统架构 嵌入式系统架构是指系统的结构、组件及其相互关系的宏观设计。它决定了系…...
Kandinsky-5.0-I2V-Lite-5s效果展示:手绘草图→线条流动+色彩渐变动态视频
Kandinsky-5.0-I2V-Lite-5s效果展示:手绘草图→线条流动色彩渐变动态视频 1. 模型简介 Kandinsky-5.0-I2V-Lite-5s是一款轻量级图生视频模型,它能将静态图片转化为约5秒、24fps的短视频。你只需要上传一张首帧图片,再补充一句运动或镜头描述…...
保姆级教程:用ACE-Step一键生成多语言音乐,视频配乐不求人
保姆级教程:用ACE-Step一键生成多语言音乐,视频配乐不求人 你是不是也遇到过这样的烦恼?精心剪辑的视频,万事俱备,就差一段能完美烘托氛围的背景音乐。翻遍免费音乐库,要么风格不搭,要么听腻了…...
Hudi 生产问题排障-乱序Upsert入湖数据丢失
一、背景与问题在大数据流式处理领域,乱序一直是一个无法越过的问题,如何正确处理乱序数据也是流式组件不断努力优化的方向,比如FLink提供的watermark机制(forBoundedOutOfOrderness/allowedLateness/sideOutputLateDataÿ…...
手把手教你用C语言解决Modbus TCP从站多主站连接的3个典型问题(含select使用避坑)
深度解析Modbus TCP从站多主站连接的三大实战难题与优化方案 在工业自动化领域,Modbus TCP协议因其简单可靠的特点被广泛应用于设备间通信。但当从站需要同时处理多个主站(如SCADA系统、HMI人机界面和测试工具)的连接请求时,开发者…...
OpenClaw性能优化指南:千问3.5-35B-A3B-FP8长任务处理技巧
OpenClaw性能优化指南:千问3.5-35B-A3B-FP8长任务处理技巧 1. 长任务处理的痛点与优化思路 当我第一次尝试用OpenClaw对接千问3.5-35B-A3B-FP8模型处理复杂多模态任务时,遇到了几个典型问题:一个包含20张产品图片的分析任务,运行…...
Simulink仿真避坑指南:三相异步电机调压调速,你的转速波形为什么震荡不稳?
Simulink三相异步电机调压调速实战:从波形异常到稳定输出的深度调优 当你在Simulink中搭建完三相异步电机调压调速模型,满心期待地点击"运行"按钮,却发现转速波形像过山车一样上下震荡——这种挫败感我深有体会。作为一名经历过无数…...
STM8S001单片机:8引脚高性价比嵌入式开发方案
1. STM8S001单片机:小身材大能量的性价比之王 在嵌入式开发领域,我们常常陷入一个两难选择:要么使用功能强大但引脚众多、价格昂贵的高端MCU,要么选择功能简陋、开发环境不友好的廉价芯片。STMicroelectronics最新推出的STM8S001系…...
交付验收前批量筛一遍配图质量:桌面工具用法记录
如果你经常遇到这种场景:项目交付包里附带大量截图、现场照片,甲方要求「明显糊的、过曝的别混进来」,但文件夹嵌套很深,人工抽查像抽奖。可以试一款只做「打分按档归类」的 Windows 桌面工具,全称【批量图片质量检测筛…...
OpenBMC实战:phosphor-bmc-code-mgmt仓库代码逻辑全解析(附避坑指南)
OpenBMC实战:phosphor-bmc-code-mgmt仓库代码逻辑全解析(附避坑指南) 在嵌入式系统开发领域,BMC(Baseboard Management Controller)固件的可靠更新机制是确保服务器稳定运行的关键环节。作为OpenBMC项目的核…...
