Spring Cache 入门笔记
1. 什么是 Spring Cache?
想象一下,你的应用程序有一个方法,需要从数据库查询一些不经常变化的数据,比如商品分类。每次用户请求这个数据,你的代码都会执行一次数据库查询,如果访问量很大,这会对数据库造成巨大的压力,并且响应速度也会变慢。
Spring Cache 就是为了解决这类问题而生的。
它是一个基于注解的缓存解决方案,能够将方法的运行结果存储起来(通常是存储在内存或像 Redis 这样的高速缓存数据库中)。当下次用相同的参数再次调用这个方法时,Spring Cache 会直接返回之前存储的结果,而不会再执行方法体内的代码(例如,不会再去查数据库)。
核心思想: 用一个简单的注解,为你的 Java 方法添加缓存能力,从而提高应用性能和响应速度。
2. 核心概念
在使用 Spring Cache 之前,你需要理解几个关键概念:
概念 (英文) | 概念 (中文) | 解释 |
---|---|---|
Cache |
缓存 | 一个存储键值对(Key-Value)的容器。在 Spring Cache 中,它是一个逻辑上的概念,可以对应一个具体的缓存实现(如一个 ConcurrentMap,一个 Redis Hash 等)。 |
CacheManager |
缓存管理器 | 顾名思义,它是用来管理多个 Cache 实例的。你可以通过它来获取、创建或删除 Cache 。Spring Boot 会根据你的依赖和配置自动配置一个 CacheManager 。 |
@EnableCaching |
开启缓存 | 这是一个开关。在你的 Spring Boot 主启动类或任何配置类上添加这个注解,就代表 “我要开始使用 Spring Cache 的功能了!"。 |
缓存注解 | 缓存注解 | Spring Cache 的精髓所在。通过在方法上添加不同的注解(如 @Cacheable , @CachePut , @CacheEvict ),来告诉 Spring 如何操作缓存。 |
导出到 Google 表格
3. 最核心的三个注解
掌握了下面这三个注解,你就掌握了 Spring Cache 80% 的用法。
3.1 @Cacheable
:查询缓存,有则返回,无则执行并缓存
这是最常用,也是最重要的一个注解。它的作用是:
-
在方法执行前,Spring 会根据方法的参数生成一个
Key
。 -
用这个
Key
去Cache
中查找。 -
如果找到了:直接返回找到的
Value
,方法体内的代码完全不会执行。 -
如果没有找到:执行方法体内的代码,获取返回值。然后将
Key-返回值
这个键值对存入Cache
中,最后再返回这个值。
使用场景:查询操作,尤其是不经常变化的数据查询(比如,根据 ID 查询用户信息、查询商品详情等)。
示例代码:
Java
|
|
代码解释:
-
@Cacheable(cacheNames = "users", key = "#id")
-
cacheNames = "users"
: 指定了要使用的Cache
的名字叫做 “users”。你可以把它想象成数据库中的一张表名。你可以指定多个cacheNames
,如{"users", "customers"}
。 -
key = "#id"
: 这是缓存的Key
。这里使用了 Spring Expression Language (SpEL)。#id
表示使用方法参数中名为id
的值作为 Key。-
第一次调用
findUserById(1L)
时,控制台会打印 “正在从数据库中查询用户…"。 -
第二次调用
findUserById(1L)
时,控制台不会有任何输出,方法会直接返回上次缓存的结果。 -
调用
findUserById(2L)
时,因为 Key 不同,所以会再次查询数据库。
-
-
3.2 @CachePut
:更新缓存,每次都执行,并刷新缓存
有时候我们希望更新数据,并确保缓存中的数据也是最新的。这时就用 @CachePut
。
它的作用是:
-
不管缓存中有没有,方法体内的代码总是会执行。
-
方法执行成功后,将生成的
Key-返回值
存入Cache
中。如果该 Key 已存在,则会覆盖原来的值。
使用场景:更新操作。比如,更新了用户信息后,希望缓存中的用户信息也同步更新。
示例代码:
Java
|
|
代码解释:
-
@CachePut(cacheNames = "users", key = "#user.id")
-
key = "#user.id"
: 使用传入的user
对象的id
属性作为 Key。 -
每次调用
updateUser(new User(1L, "李四"))
时,控制台总是会打印 “正在更新数据库中的用户…"。 -
执行完毕后,
users
缓存中 Key 为1L
的值会被更新为返回的User
对象。这样下次findUserById(1L)
就能获取到最新的用户信息了。
-
3.3 @CacheEvict
:删除缓存
当数据被删除时,我们也应该把缓存中对应的数据清理掉,避免用户获取到脏数据。
它的作用是:根据指定的 Key
,从 Cache
中删除对应的条目。
使用场景:删除操作。
示例代码:
Java
|
|
代码解释:
-
@CacheEvict(cacheNames = "users", key = "#id")
-
调用
deleteUser(1L)
后,Spring Cache 会将users
缓存中 Key 为1L
的数据删除。 -
一个有用的属性:
allEntries = true
。如果设置为true
,它会清空整个"users"
缓存,而不是只删除某个 Key。例如@CacheEvict(cacheNames = "users", allEntries = true)
。
-
4. 如何在 Spring Boot 项目中使用
在 Spring Boot 中使用 Spring Cache 非常简单,只需三步。
第一步:添加依赖
在你的 pom.xml
文件中,添加 Spring Cache 的启动器依赖。
XML
|
|
第二步:开启缓存功能
在你的主启动类上添加 @EnableCaching
注解。
Java
|
|
第三步:在方法上使用注解
就像上面的例子一样,在你的 Service 方法上添加 @Cacheable
, @CachePut
, @CacheEvict
注解即可。
默认的缓存是什么?
如果你只完成了上面三步,Spring Boot 默认会使用 ConcurrentHashMap
作为缓存。这意味着缓存是存储在应用程序的内存中的。这对于单个应用实例的简单场景是够用的,但有以下缺点:
-
应用重启后缓存会全部丢失。
-
在分布式或集群环境下,每个应用实例都维护自己的缓存,无法共享。
因此,在生产环境中,我们通常会集成专业的缓存中间件,如 Redis。
5. 集成 Redis作为缓存
将 Spring Cache 的底层实现替换为 Redis 非常流行且简单。
第一步:添加 Redis 依赖
在 pom.xml
中添加 spring-boot-starter-data-redis
。
XML
|
|
第二步:配置 Redis 连接
在 application.properties
或 application.yml
文件中配置 Redis 的地址、端口等信息。
application.properties
示例:
Properties
|
|
application.yml
示例:
YAML
|
|
完成了!
是的,就这么简单。Spring Boot 的自动配置机制非常强大。当它检测到 Redis 的依赖和配置后,会自动创建并配置一个 RedisCacheManager
来替代默认的 ConcurrentHashMap
缓存。
你的 Java 代码(@Cacheable
等注解)完全不需要做任何改动。这就是 Spring Cache 设计的优雅之处:业务代码与具体的缓存实现是解耦的。
6. 高级主题和常用配置
6.1 自定义 Key 生成策略
默认情况下,Key 的生成规则是:
-
如果没有参数,Key 是一个
SimpleKey.EMPTY
常量。 -
如果只有一个参数,Key 就是这个参数的实例。
-
如果有多个参数,Key 是一个包含了所有参数的
SimpleKey
。
大多数情况下,使用 SpEL key="..."
属性就足够了。但你也可以创建全局的 Key 生成器。
6.2 条件缓存 condition
和 unless
-
condition
: 在方法执行前判断,只有条件为true
,才会走缓存逻辑(查询或存入)。 -
unless
: 在方法执行后判断,只有条件为false
,才会将方法的返回值放入缓存。通常用来过滤掉不希望缓存的结果(比如,返回值为null
)。
示例:
Java
|
|
#result
是 SpEL 中一个特殊的变量,代表方法的返回值。
6.3 统一配置缓存过期时间 (TTL)
在 application.properties
或 application.yml
中可以统一配置缓存的过期时间。
application.properties
示例:
Properties
|
|
application.yml
示例:
YAML
|
|
6.4 @Caching
组合注解
如果你想对一个方法应用多个缓存操作,比如同时清除多个缓存,可以使用 @Caching
。
Java
|
|
这个例子在更新用户后,既清除了该用户的单条缓存,也清除了一个可能存在的用户列表缓存。
7. 总结
Spring Cache 是一个非常实用且强大的工具,它通过声明式的方式(注解)将缓存逻辑与业务逻辑解耦,让开发者能更专注于业务本身。
入门学习路径建议:
-
理解核心思想:通过缓存减少对慢速资源的访问。
-
掌握三大注解:
@Cacheable
(查询),@CachePut
(更新),@CacheEvict
(删除)。 -
实践操作:在 Spring Boot项目中,通过引入依赖、开启注解、配置
application.yml
来集成 Redis。 -
深入学习:探索
key
的 SpEL 写法、condition
/unless
条件缓存以及统一的过期时间配置。