Doctrine二级缓存并非开个开关即生效,需显式配置元数据、查询、结果三类缓存驱动,并手动调用useResultCache();findBy()等Repository方法默认不走结果缓存,命中率低主因是未调用缓存方法、缓存键冲突或驱动配置错位。

二级缓存不是开个开关就生效的
Doctrine 在 Symfony 2/3 中默认不启用二级缓存,query_cache_driver 和 result_cache_driver 是两套独立机制,且都不自动覆盖 findBy()、findOneBy() 这类 Repository 方法。你看到“缓存已配置”,不代表查询真进了缓存——绝大多数慢查询依然在裸跑。
命中率低的三个典型原因
缓存配置了但没命中的常见情况:
-
useResultCache(true)没调用:只有createQuery()创建的 Query 对象才支持该方法;$repo->findOneBy(['id' => 123])完全绕过结果缓存 - 缓存键冲突或失效:含
NOW()、RAND()、CURRENT_TIMESTAMP的 DQL 语句被 Doctrine 自动标记为不可缓存,哪怕你硬设了setResultCacheLifetime() - 缓存驱动写错位置:比如把
result_cache_driver配在metadata_cache_driver下,实际生效的是元数据缓存,和查询结果无关
怎么验证缓存是否真在工作
别信配置文件,看运行时行为:
- 开发环境打开 Web Profiler → “Doctrine” 面板,找 “Result cache hits / misses” 统计项,值为 0 就说明没走结果缓存
- 在 Redis CLI 里执行
redis-cli keys "doctrine_*",确认是否有以doctrine_result_cache_开头的 key 存在 - 加一行日志:
$query->useResultCache(true, 3600, 'test_key')->getResult();,然后查 Redis 是否写入对应 key,再改参数重跑看 key 是否变——不变说明缓存键生成逻辑没触发更新
提升命中率的关键实操点
缓存不是越多越好,而是越稳越准:
- 主键查询(
find($id))优先走自定义缓存层,而不是依赖 Doctrine 结果缓存;它更可控、键更确定、TTL 更易管理 - 对
findBy()类查询,只缓存条件数组键名固定、值为字符串/整数(不含null、DateTime、对象)的场景,否则缓存键会因序列化差异而分裂 - 禁用 Doctrine 默认的
query_cache_driver:它缓存的是 AST 和执行计划,但在高并发下容易因锁竞争拖慢,专注用result_cache_driver缓存最终数据更实在 - 缓存键里拼入版本号(如
"user_list_v2"),而不是靠删 key 失效;改版时只需更新parameters.yml里的cache_version_user值



















