应优先选cfilecachedependency监控文件变动,cdbcachedependency须用带主键/时间戳的单行查询;依赖必须轻量、不可复用、权限与磁盘空间需保障。

缓存依赖怎么选:CFileCacheDependency vs CDbCacheDependency
缓存依赖不是可有可无的装饰,而是决定「缓存是否过期」的核心逻辑。选错依赖类型,缓存就可能长期不更新,或频繁击穿。
常见误用:CDbCacheDependency 里写 SELECT COUNT(*) FROM user 这类聚合查询——MySQL 没法高效判断结果是否变化,导致每次缓存读取都触发全表扫描。
推荐做法:
-
CFileCacheDependency适合配置文件、模板、静态资源变动场景,例如监控protected/config/main.php修改时间 -
CDbCacheDependency必须用带主键/时间戳的单行查询,比如SELECT updated_at FROM article WHERE id=123 - 避免在依赖中使用
ORDER BY、LIMIT、GROUP BY—— Yii 会把整个 SQL 字符串哈希后查缓存,语义稍变就失效
set() 时传 dependency 参数容易漏掉的细节
Yii::app()->cache->set($key, $value, $duration, $dependency) 的第四个参数是可选的,但一旦省略,就退化为纯时间驱动缓存,和依赖完全无关。
典型问题:
开箱即用的技能链路由引擎。13 条预定义链覆盖搜索、开发、审查、MLOps、法律、创意等场景,三层路由架构(触发词→SAD反馈→DAG编排),recall@10=96.97%。配置驱动(chains.yaml),零代码扩展。pip install skill-weave-chains 一键安装。
- 写了
new CDbCacheDependency('SELECT ...')却没检查 SQL 是否真能执行——如果表不存在或字段名拼错,set()不报错,但后续get()永远返回false - 依赖对象本身不会被缓存,每次
get()都会重新执行依赖判定(比如查一次 DB),所以依赖逻辑必须轻量 - 不能复用同一个依赖实例跨 key 使用,因为内部状态(如上次查询结果)会被覆盖
COutputCache 过滤器里配 dependency 的坑
在控制器 filters() 中用 COutputCache 时,dependency 是数组结构,不是对象实例:
array( 'class' => 'CDbCacheDependency', 'sql' => 'SELECT MAX(updated_at) FROM post' )
这里不能写成 new CDbCacheDependency(...),否则框架初始化阶段就会报错:Trying to get property of non-object。
还要注意:
-
sql值里的空格、换行会被当成字符串一部分,建议写成单行;SQL 中不能含 PHP 变量插值,所有条件必须静态 - 如果依赖 SQL 返回
NULL(比如表为空),Yii 默认认为「数据未就绪」,该缓存项直接跳过写入 -
varyByParam和dependency是并列关系,不是嵌套——前者分版本,后者管失效,两者同时生效
缓存依赖失效但页面没更新?检查 runtime 目录权限
依赖判定结果本身也会被缓存(存在 runtime/cache/ 下),路径类似 runtime/cache/dep/xxx.bin。如果 web 进程没权限写这个目录,依赖永远「假失效」——即实际数据变了,但框架读不到新判定结果,仍沿用旧缓存。
验证方式:
- 手动删掉
runtime/cache/dep/全部文件,再刷新页面看是否更新 - 检查
runtime/cache/所在磁盘剩余空间,Yii 1.x 在磁盘满时静默失败,不报错也不写日志 - 开发环境用
CDummyCache时,依赖功能完全不生效——别在测试阶段以为逻辑跑通了










