forceDelete()会跳过软删除逻辑,直接执行物理DELETE语句,不触发模型事件、不检查属性约束,仅对已加载的模型实例有效,且不可逆。

Force Delete 会跳过软删除逻辑,直接执行 SQL DELETE
调用 forceDelete() 不会触发模型的 deleting 或 deleted 事件,也不会检查 $dates、$casts 等属性是否影响字段值。它本质是绕过 Eloquent 生命周期,拼接一条裸 DELETE FROM ... WHERE ... 语句发给数据库。
常见错误现象:调用 forceDelete() 后关联数据没删(比如没配 onDelete('cascade')),或事务中没手动处理外键约束导致报错 Integrity constraint violation。
- 只对已查询出的模型实例有效(即必须先
find()或first(),不能链式调用where(...)->forceDelete()) - 若模型启用了软删除(含
SoftDeletestrait),forceDelete()是唯一能真正清掉记录的方法 - 不支持批量强制删除 ——
Model::where(...)->forceDelete()会报错,得改用Model::where(...)->delete()(这其实是软删除)或原生DB::delete()
如何安全地批量强制删除软删除记录
想删掉所有 deleted_at IS NOT NULL 的旧数据?别碰 forceDelete() 批量用法。正确姿势是组合 DB::table() + 原生 SQL 或分页 + 循环调用实例方法。
推荐分页清理(避免内存溢出和超时):
立即学习“PHP免费学习笔记(深入)”;
use Illuminate\Support\Facades\DB;
$batchSize = 1000;
do {
$ids = DB::table('users')
->whereNotNull('deleted_at')
->limit($batchSize)
->pluck('id');
if ($ids->isEmpty()) break;
DB::table('users')->whereIn('id', $ids)->delete();
} while (true);
- 用
DB::table()绕过模型层,不加载 Eloquent 实例,速度快、内存低 - 不要用
Model::onlyTrashed()->forceDelete()—— 这行不通,Eloquent 不支持 - 如果必须走模型逻辑(比如要触发自定义清理逻辑),就用
Model::onlyTrashed()->chunk(200, function ($models) { $models->each->forceDelete(); }),但注意内存和性能开销
forceDelete() 和 restore() 能否混用?
可以,但要注意顺序和状态一致性。调用 restore() 只会把 deleted_at 设为 NULL,不会“撤销”已执行的 forceDelete() —— 因为那条记录已经从数据库里消失了。
-
forceDelete()是不可逆操作,没有回收站 -
restore()只对仍存在于表中、且deleted_at != NULL的记录生效 - 误删后只能靠备份恢复,或提前在
deleting事件里写日志 / 同步到归档表 - 生产环境建议加确认开关:
if (app()->environment('production')) { throw new Exception('Force delete disabled in prod'); }
为什么 sometimes forceDelete() 不生效?
最常见原因是模型没被正确加载,或者主键值异常。比如用 Model::where(...)->first() 拿到的是空对象,再调 forceDelete() 就静默失败(返回 false,但没抛异常)。
- 务必检查返回值:
if (!$user->forceDelete()) { Log::error('Force delete failed for user '.$user->id); } - 主键不是
id?确保模型设置了protected $primaryKey = 'uuid';,否则forceDelete()仍按id拼 WHERE 条件 - 数据库有触发器或外键限制?
forceDelete()不会帮你处理级联,得提前用DB::statement()关闭外键检查(不推荐)或手动删关联表 - MySQL 严格模式下,如果
deleted_at字段类型是DATETIME但值为'0000-00-00 00:00:00',可能被当成非法值导致条件匹配失败
forceDelete() 前,最好确认三点:记录确实该删、关联已处理、备份已就绪。



















