Redis缓存需按业务设不同过期时间,应避免全局TTL配置,可通过自定义KeyGenerator嵌入TTL信息、重写RedisCacheManager返回差异化TTL的RedisCache实例,或直接使用RedisTemplate.set()配合expire()手动控制,确保原子性与序列化一致。

Redis缓存怎么按业务设不同过期时间
不能靠全局 redisTemplate 的默认 TTL,得让不同缓存键(比如用户信息、商品列表、配置项)走各自设定的过期策略。核心是绕过 Spring Cache 抽象层的统一 timeToLive 配置,把 TTL 控制权交还给具体方法或键生成逻辑。
用 @Cacheable 的 unless + 自定义 KeyGenerator 实现动态 TTL
Spring Cache 本身不支持 per-entry TTL,但可以利用 @Cacheable 的 unless 属性配合自定义 KeyGenerator 在生成缓存键时“埋入”TTL 信息,再配合自定义 CacheManager 解析并设置过期时间。
-
KeyGenerator返回的 key 必须可序列化,建议用String或byte[],避免用含复杂对象的 key - 在 key 字符串里拼入 TTL(如
"user:123:t5m"表示 5 分钟),或者用 Map 包装 key + ttl 元数据(需配套自定义RedisCache解析) - 别依赖
unless做 TTL 判断——它只控制是否缓存,不控制已存入的过期行为
自定义 RedisCacheManager 并重写 getCache() 方法
关键不是换掉 RedisCacheManager,而是让它返回的每个 RedisCache 实例能识别调用上下文里的 TTL 指令。最稳的方式是继承 RedisCacheManager,重写 getCache(String name),根据 cacheName 返回带不同默认 TTL 的 RedisCache 实例。
- 提前定义好 cacheName 映射关系,比如
"userCache" → 30m、"configCache" → 24h - 构造
RedisCache时传入RedisCacheConfiguration,其中entryTtl设为对应值(注意:这个值仍可被@Cacheable#cacheNames+ name 匹配覆盖) - 如果用了
@CacheConfig(cacheNames = "userCache"),就确保该类所有@Cacheable方法都走同一组 TTL 规则
真正生效的方案:用 RedisTemplate 手动 set + expire
当需要精确到每个缓存操作的 TTL(比如查数据库后根据数据新鲜度决定缓存 10s 还是 2h),放弃 @Cacheable,直接用 redisTemplate.opsForValue().set() + expire() 组合。
-
redisTemplate.opsForValue().set("user:123", user, Duration.ofMinutes(5))—— 这个Duration参数会自动触发SET key value EX 300,原子性有保障 - 避免先
set再expire:网络分区或线程中断可能导致 key 永不过期 - 如果用的是 Redis 6.2+,可考虑
set(key, value, timeout, TimeUnit)重载,但底层仍是 EX/PX 语义
复杂点在于混合使用场景:一部分接口走声明式缓存(@Cacheable),另一部分走手动控制。这时候必须统一 key 命名规则和序列化方式,否则 CacheManager 和 RedisTemplate 会读不到彼此写的值。最容易被忽略的是序列化器——GenericJackson2JsonRedisSerializer 和 StringRedisSerializer 不兼容,混用会导致取出来是乱码或 null。











