开启 querycache 后数据不更新,是因为 ci4 的查询缓存基于 sql 字符串完全匹配,静态缓存结果且不感知数据库变更;缓存文件权限问题、未手动清理及多层缓存叠加会加剧该问题。

开启 queryCache 后数据不更新,不是数据库没改成功,而是查询缓存“挡住了”新数据——CodeIgniter 4 的 query cache 默认在首次执行相同 SQL 时缓存结果,后续同语句直接返回旧结果,跳过数据库查询。
queryCache 机制本身不校验数据是否变化
CI4 的 query cache 是基于 SQL 字符串完全匹配的静态缓存。只要两次查询的 SQL(含参数、空格、换行、大小写)完全一致,就复用缓存值,不管表里数据是否已被其他请求或 CLI 脚本更新。它不像 ORM 层级缓存那样感知模型变更,也不监听数据库 binlog。
- 例如:
$builder->where('status', 'active')->findAll()缓存后,即使你用 phpMyAdmin 把某条 status 改成 inactive,下次再执行这句仍返回旧列表 - SQL 中多一个空格、引号类型不同('1' vs "1")、或参数顺序微调,都会生成新 key,导致旧缓存未被覆盖,也查不到新缓存
缓存路径与权限问题让“假命中”更隐蔽
query cache 文件默认存在 writable/cache/query/ 下,若该目录不可写,CI4 不报错,而是静默跳过缓存写入——看起来像“没缓存”,实则每次都是全新查库;但若目录可写却属主不一致(如 CLI 用 root 写、Web 用 www-data 读),就会出现 Web 请求读到过期文件、CLI 清缓存却清不动的情况。
- 检查命令:
ls -ld writable/cache/query/确认权限为drwxr-xr-x且属组匹配 PHP 进程用户 - 临时验证:清空该目录后刷新页面,若数据立刻变新,说明是缓存污染而非逻辑错误
手动更新数据后未主动清理对应缓存
CI4 不提供“按条件清除 query cache”的 API。调用 $this->cache->delete('some_key') 对 query cache 无效;php spark cache:clear 只清 application cache,不碰 query cache。
- 唯一可靠方式是删除整个
writable/cache/query/目录下的文件(开发环境可行) - 生产环境建议:对关键业务(如后台管理、订单状态变更)禁用 query cache,改用更可控的 model 层缓存 + 显式
$cache->delete("user_{$id}") - 或在更新操作后加一句:
if (is_dir(WRITEPATH . 'cache/query')) { array_map('unlink', glob(WRITEPATH . 'cache/query/*')); }(慎用于高并发场景)
与页面缓存、Redis 驱动叠加造成多层拦截
如果同时启用了页面缓存($this->output->enableCache(5))和 query cache,前端看到的是页面级缓存内容;而该页面内调用的模型方法又走 query cache,等于双重锁定。更常见的是:你配置了 Redis 作为全局缓存驱动,但 query cache 仍走文件系统,两者 key 命名规则不统一,清理时顾此失彼。
- 快速定位:在控制器中加
var_dump($builder->getCompiledSelect());看实际执行的 SQL 是否带 LIMIT/OFFSET;再查看writable/logs中是否有Query cache hit日志 - 临时关闭 query cache:在
app/Config/Database.php中设'DBCache' => null或将$cachedir设为空字符串











