forceDelete() 是模型实例方法,用于物理删除软删除记录并触发 deleting/deleted 事件;不支持批量调用,批量删除需用 DB::table() 或原生 SQL;并发安全删除应加 whereNotNull('deleted_at') 条件或使用 lockForUpdate()。
用
彻底删掉软删除模型
软删除模型默认只是打个标记(
非空),不走真实 DELETE SQL。要真正从数据库删掉,必须显式调用
—— 它会跳过软删除逻辑,执行物理删除。
常见错误是直接写
,结果发现记录还在表里,只是
被设了时间;或者误以为
能绕过,但其实它根本不会触发模型事件、也不会调用
相关逻辑,连关联清理都得自己手写。
是模型实例方法,必须先查出模型(如
),再调用
它会触发
和
事件,适合需要清理附件、缓存等场景
不支持批量强制删除:没有
这种写法,批量只能用原生查询或循环调用
批量物理删除只能靠
或原生 SQL
想一次性删掉几百条软删除记录?别指望
—— 这行不通,Laravel 不提供模型作用域的强制删除链式方法。
正确做法是绕过模型,直连数据表。但要注意:这会跳过所有模型生命周期钩子(
、
)、Eloquent 访问器、以及
trait 的任何干预。
用
最简洁,也最快
如果要保留日志或触发清理逻辑,得先
拿到主键列表,再用集合分块调用
MySQL 中
不释放空间,大量删除后建议后续执行
恢复已软删除模型前,别漏掉
的条件检查
很多人在做“强制删之前先确认是否已被软删除”时,直接
,看似合理,但容易忽略并发风险:两次请求之间,另一进程可能已调用
,导致误删活跃数据。
更稳妥的做法是在数据库层面加条件判断,用原子操作确保安全。
推荐用
,一行完成「只删已软删除的」
如果必须用模型操作,先
再查再删:
本身不会报错,哪怕模型没软删除过;但它只会清空
,不会回滚其他字段变更
硬删后关联数据不会自动清理,得自己兜底
用
或
删主模型时,Laravel 的
外键约束只对数据库生效,而 Eloquent 的
事件监听、
的
方法(如
)全都不触发。
也就是说:用户被物理删了,它的头像文件、订单记录、日志条目,一个都不会少 —— 除非你提前写了对应逻辑。
在模型的
事件里手动删关联(适用于
场景)
数据库建外键时明确加
,这样
删除才真正级联
用迁移命令
检查当前外键定义,别假设它存在
最麻烦的不是删不掉,而是删得“太干净”又没留痕:物理删除后,
字段消失,连“这条数据曾经存在过”的证据都没了。真要审计或回滚,得靠备份或 binlog。
forceDelete()deleted_atforceDelete()$model->delete()deleted_atDB::table()->where()->delete()bootSoftDeletes()forceDelete()User::withTrashed()->find(123)deletingdeletedwhere(...)->forceDelete()DB::table()User::onlyTrashed()->forceDelete()deletingdeletedSoftDeletesDB::table('users')->whereNotNull('deleted_at')->delete()select idforceDelete()DELETEOPTIMIZE TABLE usersrestore()if ($user->trashed()) { $user->forceDelete(); }restore()User::where('id', 123)->whereNotNull('deleted_at')->delete()lockForUpdate()User::withTrashed()->where('id', 123)->lockForUpdate()->first()restore()deleted_atforceDelete()DB::table()onDelete('cascade')deletingHasOne/HasMany->onDelete()cascadedeletingforceDelete()ON DELETE CASCADEDB::table()php artisan schema:dumpdeleted_at