activerecord查不到记录时返回null,需判空再调用方法;save()默认不抛异常,须检查返回值;大批量插入优先用insertall();关联查询防n+1用with()预加载。

怎么用 ActiveRecord 查一条记录又不报错
查不到数据时直接调用 findOne() 返回 null,但很多人接着就调方法,结果抛出 Call to a member function xxx() on null。这不是 ActiveRecord 的问题,是没做空值判断。
正确做法:先确认返回值是否为对象再操作
-
findOne()和findBySql()等查询方法查不到时一律返回null,不是空数组或空模型 - 如果业务上「必须存在」,改用
find()->where(...)->one()+if (!$model) throw new NotFoundHttpException(); - 想自动抛异常,可用
find()->where(...)->oneOrThrow()(Yii 2.0.43+),但注意低版本不支持
save() 失败却不报错?检查这三处
save() 默认静默失败——返回 false,但不会抛异常。很多开发者只写 $model->save(); 就以为存进去了。
- 必须检查返回值:
if (!$model->save()) { var_dump($model->getErrors()); } - 常见漏掉的是
scenarios()配置:比如在update场景下,created_at字段若没进场景,即使赋了值也会被过滤掉 -
beforeSave()里return false;也会中断保存,且不提示原因——建议加日志或断点调试
批量插入用 insertAll() 还是循环 save()
10 条以内用 save() 没问题;超过 50 条,循环 save() 就是性能黑洞——每条都触发验证、事件、SQL 准备。
- 优先用
Yii::$app->db->createCommand()->insertAll(),绕过 ORM 层,快 3–5 倍 -
insertAll()不走验证、不触发事件、不填充默认值(如created_at),得自己处理 - 如果字段含表达式(如
NOW()),得用yii\db\Expression包裹:['created_at' => new \yii\db\Expression('NOW()')]
关联查询 N+1 问题怎么破
写 $post->author->name 看似简单,但如果循环 100 个 $post,就会发 100 次 SQL 查 author —— 典型 N+1。
- 用
with()预加载:Post::find()->with('author')->all() - 关联定义里别漏写
inverseOf,否则viaTable或双向关联容易重复查 -
asArray()和with()可共存,但注意:关联字段会嵌套在数组里,比如'author' => ['name' => 'xxx'],不是扁平结构
with() 失效或查出空数组。真要压测或看慢日志,得开 yii\db\Command::enableLogging = true 看实际执行了几条 SQL。php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











