掌握 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 都是整数)。问大象至少要喝多少桶水才会解渴。 …...
[特殊字符] 智能合约中的数据是如何在区块链中保持一致的?
🧠 智能合约中的数据是如何在区块链中保持一致的? 为什么所有区块链节点都能得出相同结果?合约调用这么复杂,状态真能保持一致吗?本篇带你从底层视角理解“状态一致性”的真相。 一、智能合约的数据存储在哪里…...
(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)
题目:3442. 奇偶频次间的最大差值 I 思路 :哈希,时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况,哈希表这里用数组即可实现。 C版本: class Solution { public:int maxDifference(string s) {int a[26]…...
Vue记事本应用实现教程
文章目录 1. 项目介绍2. 开发环境准备3. 设计应用界面4. 创建Vue实例和数据模型5. 实现记事本功能5.1 添加新记事项5.2 删除记事项5.3 清空所有记事 6. 添加样式7. 功能扩展:显示创建时间8. 功能扩展:记事项搜索9. 完整代码10. Vue知识点解析10.1 数据绑…...
智慧医疗能源事业线深度画像分析(上)
引言 医疗行业作为现代社会的关键基础设施,其能源消耗与环境影响正日益受到关注。随着全球"双碳"目标的推进和可持续发展理念的深入,智慧医疗能源事业线应运而生,致力于通过创新技术与管理方案,重构医疗领域的能源使用模式。这一事业线融合了能源管理、可持续发…...
1.3 VSCode安装与环境配置
进入网址Visual Studio Code - Code Editing. Redefined下载.deb文件,然后打开终端,进入下载文件夹,键入命令 sudo dpkg -i code_1.100.3-1748872405_amd64.deb 在终端键入命令code即启动vscode 需要安装插件列表 1.Chinese简化 2.ros …...
基础测试工具使用经验
背景 vtune,perf, nsight system等基础测试工具,都是用过的,但是没有记录,都逐渐忘了。所以写这篇博客总结记录一下,只要以后发现新的用法,就记得来编辑补充一下 perf 比较基础的用法: 先改这…...
现代密码学 | 椭圆曲线密码学—附py代码
Elliptic Curve Cryptography 椭圆曲线密码学(ECC)是一种基于有限域上椭圆曲线数学特性的公钥加密技术。其核心原理涉及椭圆曲线的代数性质、离散对数问题以及有限域上的运算。 椭圆曲线密码学是多种数字签名算法的基础,例如椭圆曲线数字签…...
WEB3全栈开发——面试专业技能点P2智能合约开发(Solidity)
一、Solidity合约开发 下面是 Solidity 合约开发 的概念、代码示例及讲解,适合用作学习或写简历项目背景说明。 🧠 一、概念简介:Solidity 合约开发 Solidity 是一种专门为 以太坊(Ethereum)平台编写智能合约的高级编…...
嵌入式学习笔记DAY33(网络编程——TCP)
一、网络架构 C/S (client/server 客户端/服务器):由客户端和服务器端两个部分组成。客户端通常是用户使用的应用程序,负责提供用户界面和交互逻辑 ,接收用户输入,向服务器发送请求,并展示服务…...
处理vxe-table 表尾数据是单独一个接口,表格tableData数据更新后,需要点击两下,表尾才是正确的
修改bug思路: 分别把 tabledata 和 表尾相关数据 console.log() 发现 更新数据先后顺序不对 settimeout延迟查询表格接口 ——测试可行 升级↑:async await 等接口返回后再开始下一个接口查询 ________________________________________________________…...
