数据缓存
cache() 用于把链式查询的结果缓存到文件,下次相同查询直接读缓存,不再打库。
基本用法
// 使用默认缓存时间(取 config/database.php 的 cachetime,默认 3600 秒)
$result = Db::table('users')
->where('status', 1)
->cache()
->get();
// 指定缓存时间 300 秒
$result = Db::table('articles')
->where('published', 1)
->cache(300)
->get();
// 长期缓存 24 小时
$result = Db::table('categories')
->orderBy('sort', 'ASC')
->cache(86400)
->get();
cache($timeout) 只有一个参数:缓存时间(秒);不传时取数据库配置里的 cachetime。缓存目录与默认时长都在 config/database.php 里改:
'cachetime' => 3600, // 缓存时间(秒)
'cachedir' => ROOT_PATH . 'runtime' . DS . 'db' . DS, // 缓存目录(可选)
参数与生效范围
cache(0)的过期时间就是当前秒,等于不缓存——不要用它表示“永久缓存”,要长期缓存就写足够大的秒数。- 缓存只作用于返回结果集的查询(
select、show、describe、explain等)。 - 以类名指定
PDO::FETCH_CLASS的查询不走缓存,避免把数组还原成对象时出偏差。 - 缓存目录需可写,不存在时框架会自动创建。
写库后自动失效
不需要等缓存到期,也不需要手工删缓存文件。启用查询缓存后,缓存目录里会生成一个代际文件 db.epoch;每次写库都会更新它,而缓存文件名里带着代际号,旧文件因此整体失联,下次读取会自动重建:
insert()、insertGetId()、update()、delete()、inc()、dec()、invert()/toggle()、touch()truncate()、drop()- 原生 SQL 写入:
Db::query('UPDATE ...')->exec()
代价是每次写库多一次极小的文件写。完全没有使用查询缓存的站点不产生任何额外开销——写库路径只做一次文件存在性探测。
缓存键与多库隔离
缓存键由「连接标识 + 完整 SQL + 绑定参数」组成,连接标识包含驱动、主机、端口、库名与表前缀。因此:
- 同一条 SQL 换了绑定参数,不会命中原先的缓存;
- 多个数据库共用一个
cachedir也不会串味——A 库的结果不会被 B 库读到。
过期与清理
过期条目在下次读到同一个键时被删除。目录里遗留的过期文件、旧代际文件和写入中断留下的 .tmp 会被自动回收(低概率触发,不影响请求结果)。需要立刻清空时,可以显式调用:
use startmvc\core\db\DbCache;
$dir = ROOT_PATH . 'runtime' . DS . 'db' . DS;
$removed = (new DbCache($dir))->collectGarbage(true); // 返回回收的文件数
直接删除 cachedir 下的所有文件也可以,代价是丢掉全部查询缓存(后续访问会按需重建)。
注意事项
- 结果以 JSON 写入文件;非法 UTF-8(例如 GBK 字符串)的结果不会写入缓存,也不会留下坏文件。
- 空结果集(
[])与单行查询无记录(false)同样会被缓存,避免空结果反复打库。 - 缓存不区分事务状态:不要在事务未提交时缓存“中间态”的查询结果,回滚后它会留在缓存里直到过期。
config/cache.php的autoFlushTag是「Cache 标签缓存」的配置,与这里的查询缓存无关。