redis缓存不会自动清理,需结合ttl、淘汰策略与业务层显式失效。spring cache不感知过期,@cacheable不续期,主动清理须由业务逻辑触发,如@cacheevict或redistemplate操作。

Spring Boot 集成 Redis 后,缓存空间不会“自动清理”——Redis 本身靠过期策略(TTL)和淘汰策略(maxmemory)兜底,但 Spring Cache 层不主动触发清理,也不感知 key 是否已过期。你得明确:是想清过期数据、腾内存,还是删业务缓存?方法完全不同。
Redis 自身的过期清理靠惰性+定期删除,不是“定时任务”
Redis 不会用 cron 或后台线程每秒扫描过期 key。它只做两件事:GET 等访问时检查并删(惰性),以及每 100ms 随机抽 20 个带 TTL 的 key 扫描(定期)。这意味着:
- 长期没人访问的过期 key 会一直占内存,直到被定期扫描到或下次访问
- 如果
maxmemory没设,内存可能持续增长,直到 OOM - 定期删除最多耗时 25ms,且只在过期比例 >25% 时重复,所以清理有延迟(几秒到几分钟都可能)
@Cacheable 缓存无法自动续期,TTL 一旦写入就固定
RedisCacheManager.setExpires() 或 entryTtl 配置只在缓存首次写入时生效,后续 @Cacheable 命中读取不会刷新 TTL。常见误操作包括:
- 以为加了
sync = true就能续期 —— 它只控制并发写入,不影响 TTL - 改了配置但没重启应用,
RedisCacheManager实例没重建,新 TTL 不生效 - 用
redisTemplate.opsForValue().set(key, value, duration, ...)覆盖写入 —— 这会重设 TTL,但破坏了@Cacheable的语义,且可能丢掉原有数据结构(比如 hash)
真要续期,必须绕开 Spring Cache,用 Lua 脚本原子执行 GET + EXPIRE,或者手动 get() 后再 expire()(注意检查返回值是否为 true)。
主动清缓存必须靠业务逻辑,不能依赖“自动”
Spring Boot 里没有“自动清理某类缓存”的开关。你得自己决定什么时候删:
- 数据变更时:用
@CacheEvict(value = "users", key = "#user.id")精准失效 - 批量清理时:调
redisTemplate.getConnectionFactory().getConnection().flushDb()(慎用,清空整个 DB) - 按前缀清理时:用
redisTemplate.keys("user:*")获取 key 列表再逐个delete()(注意生产环境禁用KEYS命令,改用SCAN) - 定时清理冷数据:写个
@Scheduled任务查PTTL,删掉剩余 TTL 小于阈值的 key(需自己实现,Spring 不提供)
真正容易被忽略的是:Redis 的“自动清理”只是保底机制,不是业务层的缓存管理方案。过期时间设计、淘汰策略选型(allkeys-lru 还是 volatile-ttl)、以及业务代码里的显式失效,三者缺一不可。别指望配个 entryTtl 就万事大吉。











