在ThinkPHP中恢复软删除数据需先用onlyTrashed()定位实例再调用restore()实例方法,失败返回false;物理删除必须配合force()使用delete()或destroy()。

在ThinkPHP中恢复已被软删除的数据记录,必须先确认模型启用SoftDelete、数据库字段可空且名称匹配,再通过onlyTrashed()查出目标实例后调用restore();若需彻底物理删除,则必须配合force()标记并走模型delete()或destroy()方法,否则仍会执行软删而非清行。
恢复单条软删除记录
第一步:在控制器或逻辑层中,用onlyTrashed()显式定位已软删的记录,例如UserModel::onlyTrashed()->find(123)。这一步不能写成UserModel::where('id', 123)->onlyTrashed()->find(),因为onlyTrashed()必须在查询构造器最前端链式调用,否则框架完全忽略它。
第二步:检查返回值是否为有效模型实例。如果返回null,说明该ID根本不在软删状态(可能从未删过、已被硬删、或字段配置错误),此时调用restore()毫无意义。
第三步:对非null实例调用$user->restore()。注意【restore()是实例方法,不能静态调用】,UserModel::where('id', 123)->restore()会直接报错“Call to undefined method”。
立即学习“PHP免费学习笔记(深入)”;
第四步:务必检查restore()返回值。它静默失败时不抛异常,只返回false——常见原因是delete_time字段类型不是NULL、模型未use SoftDelete、或字段名声明不一致。若返回false,立刻中断流程并排查配置。
按条件批量恢复软删数据
方法一:用Db类直写UPDATE(最快,无事件)
执行Db::name('user')->where('delete_time', 'not null')->where('status', 1)->update(['delete_time' => null])。这一步绕过模型,不触发restoring/restored事件,但效率高、可控性强。注意【MySQL严格模式下向NOT NULL字段写null会直接报错】,务必确认delete_time字段定义为DATETIME NULL或BIGINT UNSIGNED NULL。
方法二:用模型分块查+逐条restore(带事件,安全)
执行UserModel::onlyTrashed()->where('status', 1)->chunk(500, function ($users) { $users->each->restore(); });。chunk自动分页避免内存溢出,each->restore保证每条都走模型逻辑,能触发事件钩子和关联校验。但性能比Db直写慢,且restore()静默失败时不会中断整个chunk,需在闭包内加返回值判断。
彻底物理删除软删数据
必须用force()配合delete()或destroy(),这是唯一合法路径。直接写SQL或用Db::delete()会跳过所有模型层逻辑,丢失deleting/deleted事件、关联清理和日志埋点。
单条物理删:UserModel::onlyTrashed()->where('id', 123)->force()->delete()✅ 正确写法,先锁定软删状态再强制真删。
批量物理删:UserModel::onlyTrashed()->where('delete_time', 'force()->delete()✅ TP6支持;TP5请改用UserModel::destroy($ids, true),其中$ids需先通过onlyTrashed()->column('id')获取。
危险操作示例:UserModel::where('id', 123)->force()->delete()⚠️ 若该记录未软删过,force()仍会把它物理删掉——你本意可能是恢复或忽略,结果数据永久丢失。



















