发布于2026-07-06 阅读(0)
扫一扫,手机访问
先说一个常见误区。在 ThinkPHP 里,模型查询缓存如果只靠 cache(true) 简单一设,效果很可能让你失望——它只负责写入,却不会自动读取,本质上不构成真正的缓存机制。要做到有效缓存,需要手动统一 key 的生成逻辑、显式读取、以及用 toArray() 序列化后再存入。否则,哪怕接口里查十次,数据库依然得跑十次。

常见的误区是:认为 UserModel::where('status', 1)->cache(true)->select() 执行两次,第二次就能从缓存里取。事实并非如此。第一次执行时数据确实会写入缓存,但 key 是随机或默认生成的;第二次由于没有显式指定 key,也无法自动匹配,框架直接就重新查询数据库了。缓存沦为了“单次快照”,尤其在列表页或 API 多次调用的场景下,和没开缓存几乎没有区别。
问题的根源在于,cache(true) 只在查询执行后将结果塞进缓存,但框架不具备内置的 key 推导逻辑——它不会在下次请求时自动去缓存里找。你调用完全相同的链式查询,它照旧查数据库。
UserModel::where('status', 1)->cache(true)->select() 执行两次,第二次就不走库了。对于单条记录的缓存查询,最省心的选择是使用已经封装好的方法。它内部已经处理好了 key 生成、反序列化、空值兜底这些细节,可以做到自动读写闭环。
UserModel::findOrEmpty($id, ['cache' => ['tag' => 'user']])。这个方法会自动生成类似 think_model_user_123 的 key,并且在读取时自动去缓存里匹配。'expire' => 3600。当需要批量失效时,可以使用 Cache::tag('user')->clear() 清除所有带有该 tag 的缓存。where('email', $e) 这种,就需要手动管理 key 了。手动缓存虽然看起来很自由,但实际操作中,错一个字符或漏掉一个 toArray(),就可能导致缓存命中失败,甚至反序列化时直接报错。
md5(json_encode($query->getOptions())) 或者按照业务语义来命名,比如 'user_list_status_1'。千万不要用 time() 或随机数,否则每次生成的 key 都不同,缓存就失去了意义。Cache::tag('user')->get($key) 尝试从缓存获取数据。如果命中,直接返回;如果没命中,再执行 $result = $query->select() 去数据库查询。$result 返回的是一个 Collection 对象。如果直接将其存入缓存,后续反序列化会报错。务必使用 $result->toArray() 将其转为数组后再存入:Cache::tag('user')->set($key, $result->toArray(), 3600)。对于带有 distinct(true) 或 group() 的查询,直接使用 cache(true) 是个高风险的作法。这类查询的缓存 key 很容易因为字段顺序、空格或者别名差异而错位。同时,查询结果的结构也不稳定,比如可能包含聚合字段,手动缓存的难度和风险都明显更高。
Db::name('order')->distinct(true)->field('user_id')->cache(true)->select()。每次执行此查询,框架生成的 key 可能都不一样,缓存形同虚设。$key = 'order_distinct_user_ids'; $data = Cache::tag('order')->get($key) ?: Cache::tag('order')->set($key, Db::name('order')->distinct(true)->field('user_id')->select()->toArray(), 1800)。group() 查询,还要特别警惕 MySQL 5.7 及以上版本的 ONLY_FULL_GROUP_BY SQL 模式。在缓存之前,务必确认 SQL 语句能稳定执行。缓存本质上不是开关,而是一种契约:写入时怎么拼接 key、怎么序列化,读取时就必须一模一样。最容易忽略的两个环节是 Collection 对象的直接缓存,以及 file 驱动在高并发下的表现。这两个问题一旦出现,缓存非但不能提升性能,反而会变成拖垮系统的负资产。
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
正版软件
正版软件
正版软件
正版软件
正版软件
1
2
3
7
8