商城首页欢迎来到中国正版软件门户

您的位置: 首页 > 文章列表 > 编程开发 > ThinkPHP如何防止缓存穿透_ThinkPHP空值缓存策略说明【说明】

ThinkPHP如何防止缓存穿透_ThinkPHP空值缓存策略说明【说明】

  发布于2026-07-08 阅读(0)

扫一扫,手机访问

说实话,ThinkPHP 默认对查不到的数据返回 null,而问题在于,Cache::get() 一遇到 null 就不会写入缓存——这相当于把缓存穿透的门给敞开了。空值不能直接存 null,必须用占位符加上明确的 TTL 才有效。

为什么 Cache::set('key', null, 300) 没用?

ThinkPHP 的 Redis 驱动在处理序列化时,会直接跳过 null,或者把它转成空字符串,结果就是根本没写进 Redis。更麻烦的是,某些版本里,存 null 会被当作永久缓存——后续的真实数据再也刷不进去,这才是真正的灾难。

  • 验证方法很简单:用 redis-cli 直接 GET key,如果返回 (nil) 或空响应,说明压根没存成功。
  • 如果用的是 file 驱动,写 null 会生成非法文件名,静默失败,去 runtime/cache/ 里也找不到对应文件。
  • 千万别依赖 Cache::remember() 来自动处理空值——它只在回调返回非空时才缓存,空值一样会被漏掉。

空值缓存的正确写法(TP6/7)

所有查询入口必须统一走“先查缓存 → 查不到再查 DB → 无论是否查到都写缓存”这条逻辑,而且空结果必须用可识别的占位符来代替。

  • '__NULL__'json_encode(['_empty' => true]) 代替 null
  • TTL 必须设为短周期(比如 300 秒),避免占位符长期残留变成“假缓存”。
  • 示例:Cache::set('user_999999999', '__NULL__', 300)
  • 读取时手动判断:$data = Cache::get('user_123'); if ($data === '__NULL__') { return null; }

布隆过滤器怎么和空值缓存配合?

布隆过滤器不是缓存穿透的万能钥匙。它必须和空值缓存协同工作,否则那些漏掉的误判项照样会穿透防线。

  • 初始化命令:BF.RESERVE user_bf 0.01 100000(误差率 1%,预估容量 10w)。
  • 记住:只在数据真正写入 DB 后调用 $redis->bfAdd('user_bf', $id),不能在缓存层写入时就加。
  • 查询前先 $redis->bfExists('user_bf', $id),返回 false 就直接返回空,不查缓存也不查 DB。
  • 需要注意:topthink/think-bloom 扩展已经多年没更新了,集群模式下会失效,建议直接操作 Redis 命令。

空值缓存的关键不在“存什么”,而在于“所有读取点是否走同一套判断路径”。哪怕漏掉一个接口、一个中间件、一个手动绕过 Cache::get() 的地方,整个防护体系就相当于形同虚设。

本文转载于:https://www.php.cn/faq/2425015.html 如有侵犯,请联系zhengruancom@outlook.com删除。
免责声明:正软商城发布此文仅为传递信息,不代表正软商城认同其观点或证实其描述。

热门关注