缓存穿透本质是高频查询不存在的key导致db压力激增;需在拦截器校验id合法性,如数值型id需解析并判断是否大于0且在合理区间。

缓存穿透的本质是查不到 + 高频请求空值
缓存穿透不是 Redis 本身的漏洞,而是业务层没做兜底校验,导致大量查询数据库中根本不存在的 key(比如 user_id=999999999),DB 压力陡增。拦截器层校验参数有效性,是第一道防线,但必须注意:它只能拦住明显非法的输入,不能替代布隆过滤器或空值缓存。
拦截器里怎么校验 ID 类参数是否“看起来合法”
对 user_id、order_no 等字段,不能只判空或长度,要结合业务规则做轻量级合理性检查:
- 数值型 ID:用
Long.parseLong()尝试解析,捕获NumberFormatException;再判断是否在合理区间(如user_id > 0 && user_id ),避免负数、超大数直接打到 DB - 字符串型编号(如订单号):用正则预筛,例如
^ORD_[0-9]{8,12}$,不匹配的直接return ResponseEntity.badRequest().build() - 禁止透传原始用户输入进缓存 key 拼接逻辑,比如
"user:" + rawInput—— 必须先校验再拼接
为什么只靠拦截器不够?常见漏网场景
拦截器能拦住格式错误,但拦不住“格式正确但业务上不存在”的请求。比如:
Redis 缓存和数据结构管理技能。通过自然语言操作 Redis,支持 String、Hash、List、Set、ZSet、Stream 等数据结构操作。当用户提到 Redis、缓存、消息队列、会话存储时使用此技能。
- 一个真实存在的手机号
13800138000,但该号码从未注册过,仍会穿透到 DB - 分页参数
page=10000&size=100格式合法,但实际数据只有 50 页,后端未校验总页数就查库 - 前端伪造合法格式的 token 或 sign,绕过基础校验直达服务层
这类请求不会被拦截器拒绝,却依然触发缓存穿透。所以拦截器必须和 RedisTemplate.opsForValue().get() 后的空值判断、以及 setIfAbsent("user:999999999", "NULL", Duration.ofMinutes(2)) 配合使用。
拦截器校验与 Redis 空值缓存的配合要点
拦截器做完初步过滤后,后续流程仍需防御空值穿透。关键点在于:
- 空值写入缓存时,key 必须和查询 key 完全一致(比如
"user:123"),否则缓存失效 - 空值建议存为字符串
"NULL"而非null,避免序列化异常;读取时用Objects.equals(redisVal, "NULL")判断 - 空值 TTL 要短(如 2–5 分钟),太长会掩盖真实数据上线,太短起不到保护作用
- 如果用了
@Cacheable注解,它默认不缓存null,必须显式配置unless = "#result == null"并配合自定义CacheManager支持空值
真正容易被忽略的是:拦截器校验逻辑本身不能依赖 Redis 或 DB,否则它就成了新的瓶颈点——所有请求都先卡在拦截器查一次缓存,反而放大风险。










