跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客我的书AI学习GitHub 精选镜像AI工具UI配色美学关于
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
Javajava

Spring Boot 2.x 进程内缓存实战与 Cache 注解详解

Spring Boot 集成缓存功能可显著降低数据库压力。通过 spring-boot-starter-cache 依赖及@EnableCaching 注解启用缓存机制,利用@Cacheable 实现方法结果自动缓存,减少重复查询。@CacheConfig 用于统一配置缓存名称,@CachePut 和@CacheEvict 分别处理更新与清除操作。结合 SpEL 表达式可灵活控制缓存 Key 与条件,有效提升应用性能。

墨染流年发布于 2025/1/19更新于 2026/10/25110 浏览
Spring Boot 2.x 进程内缓存实战与 Cache 注解详解

随着用户规模扩大,数据库查询往往成为性能瓶颈,引入缓存是提升体验的有效手段。Spring Boot 提供了便捷的自动化配置,让我们能低侵入地为现有应用增加缓存能力。

快速入门

我们以一个基于 Spring Data JPA 访问 User 数据的案例为基础,为其添加缓存以减少数据库 IO。假设您已熟悉基础的 MySQL 读写操作,我们先回顾一下实体定义。

User 实体

@Entity
@Data
@NoArgsConstructor
public class User {
    @Id
    @GeneratedValue
    private Long id;
    private String name;
    private Integer age;

    public User(String name, Integer age) {
        this.name = name;
        this.age = age;
    }
}

数据访问接口

public interface UserRepository extends JpaRepository<User, Long> {
    User findByName(String name);
    User findByNameAndAge(String name, Integer age);
    @Query("from User u where u.name=:name")
    User findUser(@Param("name") String name);
}

为了观察缓存效果,先在 application.properties 中开启 SQL 打印:

spring.jpa.show-sql=true

修改单元测试类,插入一条用户名为 AAA、年龄为 10 的数据,并通过 findByName 函数完成两次查询:

@RunWith(SpringRunner.class)
@SpringBootTest
public class Chapter51ApplicationTests {
    @Autowired
    private UserRepository userRepository;

    @Test
    public void test() throws Exception {
        // 创建 1 条记录
        userRepository.save(new User("AAA", 10));
        User u1 = userRepository.findByName("AAA");
        System.out.println("第一次查询:" + u1.getAge());
        User u2 = userRepository.findByName("AAA");
        System.out.println("第二次查询:" + u2.getAge());
    }
}

在没有加入缓存之前执行测试,日志显示两次查询都执行了 SQL:

Hibernate: select user0_.id as id1_0_, user0_.age as age2_0_, user0_.name as name3_0_ from user user0_ where user0_.name=?
第一次查询:10
Hibernate: select user0_.id as id1_0_, user0_.age as age2_0_, user0_.name as name3_0_ from user user0_ where user0_.name=?
第二次查询:10

引入缓存

首先,在 pom.xml 中添加缓存启动器依赖:

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

接着,在主启动类上添加 @EnableCaching 注解开启缓存功能:

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

然后在数据访问接口上配置缓存注解,这里使用 @CacheConfig 统一指定缓存名称,并在具体方法上使用 @Cacheable:

@CacheConfig(cacheNames = "users")
public interface UserRepository extends JpaRepository<User, Long> {
    @Cacheable
    User findByName(String name);
}

再次运行单元测试,你会发现第二次调用 findByName 时不再执行 SELECT 语句,直接减少了数据库读取操作。如果想深入观察缓存存储,可以在测试中注入 CacheManager 查看 users 集合中的对象状态。

核心注解解析

回过头来看这里用到的两个注解分别做了什么:

  • @CacheConfig: 主要用于配置该类中会用到的一些共用缓存属性。比如这里的 cacheNames = "users",表示该接口返回的内容将存储在名为 users 的缓存对象中。如果不使用它,也可以直接在 @Cacheable 中单独配置缓存集名字。
  • @Cacheable: 标记在查询方法上。首次调用会执行方法并将结果存入缓存,后续相同参数直接返回缓存值。该注解支持多个参数来控制行为:
    • value / cacheNames: 指定缓存集合名,两者等价。
    • key: 默认使用所有参数组合作为 Key,也可用 SpEL 表达式自定义,例如 #p0 代表第一个参数。
    • condition: 满足条件时才缓存,需使用 SpEL 表达式,例如 #p0.length() < 3。
    • unless: 方法执行后判断是否缓存,常用于根据返回值决定是否缓存,与 condition 的区别在于判断时机不同。
    • keyGenerator: 指定自定义 Key 生成器,实现 KeyGenerator 接口即可,注意它与 key 互斥。
    • cacheManager / cacheResolver: 当存在多个缓存管理器或解析器时使用。

除了这两个,还有两个核心注解值得注意:

  • @CachePut: 每次都会真实调用方法,主要用于数据新增和修改操作,更新缓存内容。
  • @CacheEvict: 通常用在删除方法上,用来从缓存中移除相应数据。支持 allEntries 清空全部数据,以及 beforeInvocation 控制是在方法调用前还是调用后移除。

通过合理组合这些注解,就能灵活地管理应用内的缓存策略,显著提升数据访问效率。

目录

  1. 快速入门
  2. 引入缓存
  3. 核心注解解析

更多推荐文章

查看全部
  • Android 开发进阶指南:核心技能与避坑建议
  • MySQL 视图与触发器核心用法解析
  • 基于 Semantic Kernel 与 Pandora Box 快速构建 Code Agent
  • Java 基础:8 大基本数据类型详解及面试题
  • C++ 多线程同步之原子操作(atomic)实战
  • 本地 AI 绘画工具 Z-Image-Turbo UI 实测与使用指南
  • 低空经济新实践:无人机如何革新光伏电站巡检
  • 108 个 Python 实战项目精选:基础、算法与工程案例
  • Java 并发性能优化:如何避免伪共享
  • Claude Code 本地化部署教程:基于 Ollama 实现离线开发
  • 基于 cpolar 内网穿透实现 OpenClaw 远程访问与固定域名配置
  • 面试高频问题:线上问题解决经验整理
  • C++11 核心特性:Lambda 表达式与函数包装器详解
  • OpenClaw 部署指南:Minimax/DeepSeek 模型与飞书机器人配置
  • Python 虚拟环境管理工具 UV:从安装到高级用法
  • C++ 输入输出机制剖析:标准流、文件操作与性能调优
  • 离线语音转录工具 Whispering 本地化方案解析
  • Java在AI时代的崛起:从机器学习到AIGC全栈方案
  • AudioSeal 在 Whisper 生成音频中检测并提取原始水印
  • Web2Executable 实用指南:快速将网页封装为桌面应用

相关免费在线工具

  • Keycode 信息

    查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online

  • Escape 与 Native 编解码

    JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online

  • JavaScript / HTML 格式化

    使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online

  • JavaScript 压缩与混淆

    Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

  • Base64 文件转换器

    将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online