updateAttributes跳过验证和事件,仅更新数据库真实存在且可写的字段;updateAll纯SQL批量更新,性能高但WHERE易误操作;save(false)跳过验证但保留钩子,需显式传false;时间戳应交由TimestampBehavior管理。

updateAttributes 会跳过验证和事件,但字段必须存在且可写
直接调用 updateAttributes() 是绕过 beforeSave、afterSave 和模型规则校验的最快方式,适合只改几个固定字段(比如状态、计数器)的场景。但它不是“任意字段都能设”,而是严格依赖模型的 attributes() 返回值——即数据库表里真实存在的列名,且不能是只读字段(如主键、表达式字段)。如果传了不存在的字段名(比如拼错成 upadte_at),方法会静默忽略,不报错也不更新。
- 必须确保字段在数据库中真实存在,且未被
safe规则或scenarios()排除 - 不能更新主键字段(如
id),即使表结构允许,框架也会跳过 - 关联字段(如
user.name)或虚拟属性(如fullName)无法通过此方法更新 - 时间戳字段(
updated_at)不会自动刷新,得手动传进去:$model->updateAttributes(['status' => 1, 'updated_at' => new \yii\db\Expression('NOW()')])
updateAll 更轻量,但 WHERE 条件写错会导致全表误更新
当你要批量更新一批记录的相同字段(比如把所有待审核订单改成已审核),updateAll() 是唯一合理选择。它不加载模型、不走任何钩子、不校验,纯 SQL 执行,性能比循环 save() 高一个数量级。但它完全脱离模型上下文,WHERE 条件一旦写错(比如漏掉 AND status = 0),就可能把整张表数据刷成同一值。
- WHERE 参数支持数组格式:
['id' => [1,2,3]],也支持字符串表达式:'status = 0 AND created_at ,记得用绑定参数防注入 - 更新值中若含函数或表达式,必须用
\yii\db\Expression包裹,例如:['updated_at' => new \yii\db\Expression('NOW()')] - 不检查字段是否存在,字段名错写成
updae_time会导致 SQL 报错:Unknown column 'updae_time' in 'field list' - 执行后返回影响行数,建议判断:
if ($rows === 0) { // 没匹配到记录,可能是条件太严 }
save(false) 是折中方案,但 false 容易被忽略或误传
想保留 beforeSave 钩子、触发事件、又跳过验证时,$model->save(false) 是最自然的选择。它仍会走完整生命周期,只是跳过 validate() 步骤。问题在于那个 false 参数太容易被遗忘或误写成 0、null,而 PHP 会把它转成 true,结果验证照常跑,失败还不报错。
- 必须显式传
false,写成$model->save(0)或$model->save(null)都等价于$model->save(true) - 如果模型有
beforeSave()方法,它仍会被调用,里面对$this->attributes的修改会生效 - 注意:即使跳过验证,
rules()中定义的default值仍会填充(因为发生在load()阶段),但required不会拦截 - 慎用于用户提交数据,除非你已在控制器层做过清洗和可信判断
别用 updateAttributes 处理时间戳字段,TimestampBehavior 才是正解
很多人试图在 updateAttributes() 里手动塞 updated_at,结果发现有时更新了有时没更新,或者时间不准。根本原因是:时间戳字段应该交给 TimestampBehavior 统一管理,而不是靠人工维护。它能确保每次 save() 或 updateAll() 时自动写入,且兼容 NOW()、UNIX_TIMESTAMP()、自定义回调等多种值源。
- 行为配置里
'value' => new \yii\db\Expression('NOW()')是最稳写法,避免 PHP 时区与 MySQL 不一致 - 如果模型继承自公共基类,把行为定义放基类里即可复用,不用每个模型都重写
behaviors() - 手动更新时间戳字段,等于绕过行为逻辑,后续再调用
save()可能导致时间被二次覆盖 - 调试时发现
updated_at没变,第一反应不该是查 SQL,而是确认行为是否注册、EVENT_BEFORE_UPDATE是否命中、字段名是否拼写正确


















