缓存读取需先判null再判空字符串,二者均需特殊处理以防json解析异常;写入必须带ttl,按业务频率设值,空结果存""并设短ttl;key应统一前缀、常量化、结构化;反序列化须严格匹配数据类型。

缓存读取逻辑:先查 stringRedisTemplate.opsForValue().get(),再判空
直接用 get() 拿值,别绕弯子。返回 null 表示 Redis 里压根没这个 key;返回空字符串 "" 是你主动存的占位符(防穿透),得单独处理。常见错误是只判 != null 就放行,结果把空字符串当有效数据解析,抛 JSON parse error。
- 必须同时检查
s == null和StringUtils.isEmpty(s)(或s.equals("")) - 若为占位符,应直接 throw 异常或返回默认值,不再走后续 JSON 解析
- 不要用
JSON.parseArray(s, ...)去解析null或空串,会 NPE 或 SyntaxError
缓存写入时机:DB 查询成功后立刻 set(),且带 TTL
写缓存不是可选项,是防击穿和雪崩的底线操作。不设过期时间(set(key, value))等于埋雷——内存涨满、脏数据滞留、淘汰策略不可控。TTL 不是拍脑袋定的,要结合业务变化频率:店铺类型类静态数据用 30L 分钟足够,商品详情类半动态数据建议 5~10 分钟。
Redis 8.2.3 是一款安全优先的高性能键值存储系统。该版本紧急修复了可能引发远程代码执行(RCE)的高危漏洞(CVE-2025-62507),并解决了 HyperLogLog 及 Cuckoo Filter 等数据结构在特定场景下的崩溃问题。建议所有用户立即升级,以保障生产环境的系统稳定与数据安全。
- 务必用重载方法
set(key, value, timeout, unit),避免永久缓存 - value 必须是字符串,用
JSONUtil.toJsonStr(list)或JSON.toJSONString(obj)转,别传对象原样塞进去 - 如果 DB 查询结果为
null或空集合,按穿透方案存""并设短 TTL(如 2 分钟),不能跳过写缓存步骤
Key 设计要点:带业务前缀 + 可读性强,避免硬编码
key 写成 "shop::Type" 这种临时字符串,上线后改个名就得全项目搜替换。应该提取成常量,且体现层级和作用域。比如 cache:shop:type 比 shop::Type 更利于运维排查,也方便未来加 namespace 隔离。
- 推荐格式:
业务域:资源类型:标识,例如cache:product:hot、cache:user:profile:1001 - 避免使用拼接字符串如
"cache:" + type + ":" + id,易出错;用String.format("cache:%s:%d", type, id)或构建器更稳 - 同一业务模块的所有 key 前缀保持统一,方便
redis-cli --scan --pattern "cache:shop:*"批量清理
反序列化陷阱:用 JSON.parseArray() 还是 JSON.parseObject()?
查列表就用 JSON.parseArray(s, Type.class),查单个对象就用 JSON.parseObject(s, Type.class)。混用会导致类型转换失败——比如把单个对象的 JSON 字符串喂给 parseArray(),解析出来是 [{...}] 包裹的 List,但实际业务代码 expecting a plain object,运行时报 ClassCastException。
- 确认数据库查询返回的是
List<t></t>还是T,再选对应 JSON 方法 - FastJSON2 推荐用
JSON.parseArray(s, Type.class),别用已废弃的JSON.parseArray(s)后手动 cast - 如果缓存 value 是哈希结构(如
opsForHash().get()),注意它返回的是String,不是自动反序列化的对象










