Yii2 的 updateAll() 必须用占位符或关联数组传 where 条件,禁用字符串拼接防 SQL 注入;IN 查询直接传数组;表达式需用 Expression 包裹;不触发事件与验证,返回影响行数。

updateAll 的 where 条件里不能直接拼接变量
Yii2 的 updateAll() 是安全的批量更新方法,但它不接受字符串拼接的 SQL 片段作为 where 条件。如果你写成 updateAll($data, "id = $id") 或 "status = '$status'",就等于绕过参数绑定,存在 SQL 注入风险,而且在值含单引号、空格或 null 时会直接报错或更新错行。
正确做法永远是用占位符 + 参数数组:
- 用
['column = :val', [':val' => $value]]形式传 where - 或更推荐的关联数组形式:
['id' => $id](自动转为id = :qp0并绑定) - 多条件用
['and', ['status' => 1], ['type' => 'user']],别手拼"status=1 AND type='user'"
批量更新多个不同 ID 时必须用 in 查询 + 参数绑定
想一次更新一组指定 ID 的记录(比如 id IN (1,5,8,12)),不能把数组 $ids = [1,5,8,12] 直接塞进字符串 —— "id IN (" . implode(',', $ids) . ")" 看似能跑,但遇到 $ids 含字符串或用户输入就崩。
Yii2 原生支持数组自动展开为 IN,只要用关联数组语法:
$ids = [1, 5, 8, 12]; User::updateAll(['status' => 2], ['id' => $ids]); // 生成:UPDATE `user` SET `status`=2 WHERE `id` IN (1,5,8,12)
注意:['id' => $ids] 中的 $ids 必须是纯数值或字符串数组,不能是对象或 null 元素,否则抛出 InvalidParamException。
更新字段值里含变量,要用表达式避免被转义
如果要执行类似 “status = status + 1” 或 “updated_at = NOW()”,直接写 ['status' => 'status + 1'] 会被当成字符串字面量,导致写入字符串而非计算结果。
这时必须用 yii\db\Expression 包裹:
['status' => new \yii\db\Expression('status + 1')]['updated_at' => new \yii\db\Expression('NOW()')]- 混合场景:
['score' => new \yii\db\Expression("score + {$bonus}")]—— 注意这里{$bonus}是 PHP 变量插值,仅当$bonus是可信整数时才安全;否则仍建议用占位符:new \yii\db\Expression('score + :bonus', [':bonus' => $bonus])
updateAll 不触发事件和验证,别误当 saveAll 用
updateAll() 是原生 SQL 批量 UPDATE,跳过模型生命周期:不会调用 beforeUpdate/afterUpdate,不走规则验证,不格式化属性(比如 datetime 字段不会自动转时间戳),也不会更新 updated_at 自动时间戳(除非你显式写进 $data)。
所以它只适合「已知数据干净、只需改库」的场景。如果你依赖模型钩子、需要审计日志、或字段逻辑复杂(如密码需 hash),就该用循环 + $model->save(false),哪怕慢点也得保逻辑完整。
另外,updateAll() 返回的是影响行数(int),不是布尔值,别用 if (updateAll(...)) 判成功 —— 即使 where 不匹配任何行,也返回 0,这算正常执行,不是失败。


















