启用Redis声明式缓存需引入spring-boot-starter-cache和spring-boot-starter-data-redis依赖,添加@EnableCaching注解,并配置spring.cache.type=redis及RedisCacheManager序列化器(推荐GenericJackson2JsonRedisSerializer),确保cacheNames与key在@Cacheable/@CacheEvict中严格一致。

怎么在 Spring Boot 里启用 Redis 声明式缓存
直接加 @EnableCaching 并配好 Redis 连接,Spring Boot 就能接管缓存逻辑——但前提是它知道该用 Redis 而不是默认的 ConcurrentMap。很多人卡在这一步,不是没加注解,而是没让 Spring Cache “认出” Redis。
- 必须引入两个依赖:
spring-boot-starter-cache(提供@Cacheable等注解支持)和spring-boot-starter-data-redis(提供 Redis 实现) -
@EnableCaching要加在启动类或任意@Configuration类上,只加一次即可,重复加不报错但无意义 - Spring Boot 2.0+ 默认会自动注册
RedisCacheManager,前提是spring.cache.type=redis没被覆盖(检查application.yml是否误设为simple或none)
为什么加了 @EnableCaching 却没走 Redis
最常见原因是缓存管理器没生效:Spring Boot 发现 classpath 有 Redis 依赖,但没看到你显式配置序列化方式,就可能 fallback 到默认的空实现,或者抛出 CacheManager bean could not be found。
- Spring Boot 2.4+ 默认禁用了自动配置的
RedisCacheManager,需手动定义 Bean;2.3 及以前版本虽自动注册,但值序列化器仍是JdkSerializationRedisSerializer,导致反序列化失败且静默降级 - 必须配置序列化器,否则缓存写入是乱码,读取时抛
SerializationException或返回 null - 推荐用
GenericJackson2JsonRedisSerializer,它支持任意 POJO,但要求实体类字段可被 Jackson 访问(public 字段 or getter/setter)
cacheNames 和 key 怎么写才不出错
@Cacheable 的 cacheNames 是缓存区域名(类似数据库里的表名),key 是具体条目 ID;写错会导致缓存写到错的地方、或查不到已存的数据。
-
cacheNames不要带空格或特殊字符,建议全小写 + 下划线,如"user_profile";多个缓存区可用数组:cacheNames = {"user", "profile"} -
key推荐用 SpEL 表达式,#id表示方法参数名,#p0表示第一个参数(索引写法兼容 Kotlin/重载场景) - 避免用
key = "#root.args[0]"这类模糊写法——如果方法重载,参数顺序可能变;也别漏掉类型转换,比如整型 ID 要转字符串:key = "T(String).valueOf(#id)" - 实体类必须实现
Serializable接口(用 Jackson 序列化时非强制,但加了更稳妥)
删缓存时 @CacheEvict 不生效的典型原因
明明调了删除方法,Redis 里 key 还在,常见于 key 生成规则不一致、缓存名拼错、或没触发缓存拦截。
-
@CacheEvict默认不会调用原方法(beforeInvocation = false),所以它只删缓存,不改 DB;如果你删缓存前要先查 DB 做校验,得设beforeInvocation = true - 确保
cacheNames和key与@Cacheable完全一致,大小写、引号、表达式结果都得对得上 - 注意事务边界:如果删除方法加了
@Transactional且缓存操作在事务提交后才执行(默认行为),而事务回滚了,缓存也不会删——此时可加beforeInvocation = true强制提前删 - 测试时别只看 Java 日志,直接用
redis-cli keys "user_profile_*"看 Redis 里有没有残留 key
最容易被忽略的是:缓存穿透、击穿、雪崩这些业务层问题,声明式缓存本身不解决;它只管“该不该缓存”和“往哪写”,不负责兜底、限流或空值缓存。真要上线,得配合 @Cacheable(sync = true) 防击穿,或自己封装空对象缓存逻辑。










