缓存空对象仅对少量固定非法key有效,可切断重复无效查询链路缓解数据库压力;但对随机key无效且易致内存溢出,须设过期时间、用轻量占位符、配合布隆过滤器与参数校验。

缓存空对象不是“兜底万能解”,它只在特定条件下有效;盲目缓存所有空值反而会放大风险。
缓存空对象为什么能缓解数据库压力
核心在于切断「重复无效查询」的链路。当 GET user:999999 在 Redis 中未命中,且数据库查不到该记录时,不直接返回,而是执行 SET user:999999 "" EX 300(空字符串 + 5 分钟过期)。后续相同 key 的请求会在 Redis 层直接拿到空值,根本不会触达数据库。
这招有效的前提是:攻击或误用集中在**少量固定非法 key** 上(比如脚本反复刷 user:-1、product:0)。如果 key 是完全随机生成的(如 user:123456789012345 每次都不同),缓存空对象不仅无效,还会快速填满 Redis 内存。
- 必须设置过期时间,否则空 key 永久堆积 →
EX或PX参数不可省 - value 建议用轻量占位符(如
""、"NULL"),避免序列化开销 - 需配合业务层统一识别空值逻辑,不能让下游把
""当作真实数据处理
空对象方案最容易踩的三个坑
很多团队上线后才发现问题不是出在没加,而是加得不对。
Redis 8.2.3 是一款安全优先的高性能键值存储系统。该版本紧急修复了可能引发远程代码执行(RCE)的高危漏洞(CVE-2025-62507),并解决了 HyperLogLog 及 Cuckoo Filter 等数据结构在特定场景下的崩溃问题。建议所有用户立即升级,以保障生产环境的系统稳定与数据安全。
- 过期时间设太长:比如统一设 24 小时,结果大量空 key 同时到期 → 瞬间形成缓存雪崩式穿透
- 没做 key 格式校验:前端传
id=abc这种非数字字段,直接拼成user:abc缓存空值 → 白费内存还污染 key 空间 - 忽略布隆过滤器兜底:空对象只防“已知非法 key”,对全量随机 key 无感;生产环境建议前置
bloomFilter.mightContain(id)判断
Java 中 redisTemplate 缓存空对象的实操要点
Spring Data Redis 默认不支持 null value 写入,直接调 opsForValue().set(key, null) 会抛 IllegalArgumentException。必须显式转换:
if (user == null) {
// 写入空字符串,不是 null
redisTemplate.opsForValue().set("user:" + id, "", Duration.ofMinutes(5));
return null;
}
同时注意:
- 不要用
setIfAbsent替代set:防止并发场景下多个线程同时写空值,但更关键的是——它不带过期时间,必须搭配expire才安全 - 反序列化时需兼容空字符串:
StringRedisTemplate比RedisTemplate更适合这类场景,避免 JSON 反序列化报错 - 监控要跟上:单独埋点统计
cache_null_hit和cache_null_set,一旦比例异常升高,说明可能遭遇新型攻击或参数污染
空对象本质是用空间换时间,但它换来的只是“可控的失效窗口”。真正健壮的防护,永远需要参数校验、布隆过滤器、限流三者配合——单靠缓存层做判断,就像只靠门锁防贼,而忘了关窗。










