findOne()查再删最安全,需判空防崩溃并触发事件;deleteAll()直删性能高但绕过事件和验证,慎用于有业务逻辑的场景,大批量删除须分批异步执行。

用 findOne() 查再删,是最安全的单条删除方式
直接调用 delete() 前必须确保模型对象已加载成功,否则会抛出 Call to a member function delete() on null 错误。常见写法是先查后删:
-
$model = Article::findOne(15);—— 返回ActiveRecord实例或null - 必须判断
if ($model !== null) { $model->delete(); },否则空对象调用delete()会崩溃 - 该方式会触发模型事件(如
beforeDelete、afterDelete)和验证逻辑,适合需要业务钩子的场景 - 若 ID 不存在,
findOne()返回null,不会报错;但delete()不会执行,也不会返回 false 或 0,需靠判空捕获
deleteAll() 按条件批量删,ID 存在性不校验
跳过模型加载、直连数据库执行 DELETE 语句,性能高但绕过所有 ActiveRecord 机制:
-
Article::deleteAll(['id' => 15]);—— 推荐写法,自动参数绑定,防 SQL 注入 -
Article::deleteAll('id = :id', [':id' => 15]);—— 手动占位符,等效但更啰嗦 - 返回值是受影响行数(int),哪怕 ID 不存在也返回 0,不会报错
- 不触发任何模型事件、验证、关系级联操作;如果表有外键约束或依赖行为,这里会静默失效
- 慎用于有软删除、审计日志、关联清理逻辑的模型
别在 Web 请求里删大批量数据
用 deleteAll() 一次性删几千上万行,极易导致 MySQL 锁表、超时、连接池耗尽:
- Web 请求默认
max_execution_time=30,大删中途被 kill 后状态不可知 - 事务体积过大,binlog 膨胀,主从延迟飙升
- 正确做法是:在
console/controllers下写命令,用Query::column()分批取 ID,再用createCommand()->delete()分批删,每批后usleep(10000) - crontab 调用该命令,而非通过 URL 触发 —— 这是线上稳定性的底线
ID 字段名不一定是 id,得看模型定义
Yii 默认主键字段叫 id,但很多老项目或自定义表用的是 article_id、user_id 等:
-
Article::findOne(15)实际查的是[[primaryKey()]]返回的字段,不是硬编码id - 务必确认模型类里是否重写了
primaryKey()方法,例如:return ['article_id']; -
deleteAll(['article_id' => 15])中的键名必须和实际字段一致,否则条件永远不匹配,返回 0 却以为删成功了 - 用
var_dump(Article::primaryKey());快速验证,别凭印象写


















