RedisTemplate 是 Spring Data Redis 提供的一个核心类,封装了大量与 Redis 交互的操作方法,使用灵活、功能强大。而 Spring Cache 则是在更高抽象层上提供的一套缓存编程模型------它通过注解的方式简化缓存的使用,开发者无需直接操作 RedisTemplate 或其他底层缓存客户端,即可实现对缓存的读写与管理。
Spring Cache 并不仅限于 Redis。它是一个通用的缓存抽象层,支持多种缓存实现,例如 Ehcache、Caffeine、ConcurrentHashMap(基于内存)等。这意味着我们可以在不修改业务代码的前提下,轻松切换底层缓存存储方案。即使不配置任何外部缓存组件,Spring Cache 也能自动回退到基于内存的简单缓存实现,确保功能正常运行。
Spring Cache 中常用的几个核心注解包括:
- @EnableCaching:添加在 Spring Boot 启动类(或配置类)上,用于启用基于注解的缓存功能。
- @Cacheable:通常用于查询方法。当方法被调用时,Spring 会先尝试从缓存中查找对应的数据;如果命中,则直接返回缓存结果,避免执行方法体;若未命中,则执行方法,并将返回值存入缓存供后续使用。
- @CacheEvict:常用于新增、修改或删除操作的方法上,用于清除缓存中的一条或多条数据,确保缓存与数据源的一致性。
- @CachePut:用于更新缓存。无论缓存是否存在,都会执行方法体,并将返回值写入缓存。适用于需要强制刷新缓存的场景。
1. 使用
1. @EnableCaching:启用缓存支持
要使用 Spring Cache 的注解功能,首先需要在 Spring Boot 的主启动类(或配置类)上添加 @EnableCaching 注解,以开启基于注解的缓存管理:
java
@SpringBootApplication
@EnableCaching // 启用 Spring Cache 注解功能
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
该注解会触发 Spring 自动配置缓存相关的基础设施(如 CacheManager),从而支持后续的 @Cacheable、@CachePut 和 @CacheEvict 等注解。
2. @CachePut:更新或写入缓存
@CachePut 用于将方法的返回值写入缓存,无论缓存中是否已存在对应数据,方法体都会执行。常用于新增或更新操作后同步刷新缓存。
关键属性说明:
- value:指定缓存的"命名空间"(即缓存名称),相当于一个缓存区域。
- key:在该命名空间下唯一的缓存键。支持 Spring 表达式语言(SpEL),例如 #user.id 表示方法参数 user 的 id 属性,#result.id 表示方法返回对象的 id 属性。
java
@PostMapping("/user")
@CachePut(value = "userCache", key = "#result.id")
public User save(@RequestBody User user) {
userMapper.insert(user); // 假设插入后 user 对象包含生成的 ID
return user;
}
注意:@CachePut不会跳过方法执行,因此适用于需要强制更新缓存的场景。
3. @Cacheable:读取缓存(若存在)
@Cacheable 通常用于查询方法。Spring 会在方法调用前先检查缓存:
- 如果命中(缓存中有对应 key 的数据),则直接返回缓存结果,不执行方法体;
- 如果未命中,则执行方法,并将返回值自动存入缓存。
java
@GetMapping("/user/{id}")
@Cacheable(value = "userCache", key = "#id")
public User findById(@PathVariable Long id) {
return userMapper.getById(id); // 仅当缓存未命中时才会执行此行
}
这是提升查询性能最常用的注解,能有效减少数据库访问。
4. @CacheEvict:清除缓存
@CacheEvict 用于在方法执行后删除缓存中的数据,确保缓存与数据源的一致性。常用于删除或更新操作。
删除单条缓存:
java
@DeleteMapping("/user/{id}")
@CacheEvict(value = "userCache", key = "#id")
public void deleteById(@PathVariable Long id) {
userMapper.deleteById(id);
}
清空整个缓存区域:
通过设置 allEntries = true,可一次性清除 value 指定缓存区域中的所有条目:
java
@DeleteMapping("/user")
@CacheEvict(value = "userCache", allEntries = true)
public void deleteAll() {
userMapper.deleteAll();
}
注意:allEntries = true 会忽略 key 属性,直接清空整个缓存命名空间。
2. 设置缓存时间
默认情况下,使用 @Cacheable 或 @CachePut 注解写入 Redis 的缓存数据没有过期时间(TTL),会一直保留在缓存中。在实际项目中,为了避免缓存数据长期不更新或占用过多内存,通常需要为缓存设置合理的过期时间。
Spring Cache 通过 cacheManager 属性指定使用的缓存管理器(CacheManager),而不同的 CacheManager 实现可以配置不同的缓存策略,包括过期时间。对于 Redis,我们可以通过自定义 RedisCacheManager 来实现这一需求。
1. 创建配置类
首先,创建一个 Spring 配置类,注册一个带有 TTL(Time-To-Live)策略的 RedisCacheManager Bean:
java
@Configuration
public class SpringCacheConfig {
/**
* 定义一个缓存管理器,所有使用该管理器的缓存项默认 30 分钟后过期
*/
@Bean("cacheManager30Minutes")
public RedisCacheManager cacheManager30Minutes(RedisConnectionFactory connectionFactory) {
// 配置默认的缓存设置:设置 TTL 为 30 分钟
RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
.entryTtl(Duration.ofMinutes(30)) // 设置缓存过期时间为 30 分钟
.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(RedisSerializer.string()))
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(RedisSerializer.json()));
return RedisCacheManager.builder(connectionFactory)
.cacheDefaults(config)
.transactionAware() // 支持事务(可选)
.build();
}
}
说明:
@Bean("cacheManager30Minutes") 中的名称 "cacheManager30Minutes" 将作为该缓存管理器的唯一标识。
如果你使用的是较新版本的 Spring Boot(2.7+),建议显式指定序列化方式(如 JSON),避免默认 JDK 序列化带来的兼容性问题。
2. 设置TTL
接下来,在需要设置过期时间的缓存方法上,通过 cacheManager 属性引用我们刚刚定义的 Bean:
java
@GetMapping("/user/{id}")
@Cacheable(
value = "userCache",
key = "#id",
cacheManager = "cacheManager30Minutes" // 指定使用 30 分钟过期的缓存管理器
)
public User findById(@PathVariable Long id) {
return userMapper.getById(id);
}
这样,所有通过该方法写入 userCache 的缓存数据,都会在 30 分钟后自动过期并被 Redis 清除。