ThinkPHP软删除失效源于模型配置、数据库字段、调用方式未对齐:需正确引入SoftDelete trait并设$deleteTime与$useSoftDelete,delete_time字段须为DATETIME/TIMESTAMP且NULLABLE,默认NULL;必须通过模型方法(非Db直连)操作,并注意withTrashed()位置及关联查询显式启用。

ThinkPHP软删除失效,不是框架出错,而是模型配置、数据库字段、调用方式三者没对齐。漏掉任一环节,delete() 就会变真删,restore() 也静默失败。
检查模型是否真正启用 SoftDelete
只写 use SoftDelete; 不够,必须同时满足:
- 导入正确命名空间:
use think\model\concern\SoftDelete; - 类内声明 trait:
use SoftDelete; - 显式指定软删字段:
protected $deleteTime = 'delete_time';(即使用默认名也建议写上) - ThinkPHP 6.0.0–6.0.7 版本必须加开关:
protected $useSoftDelete = true; - 改完后运行
php think optimize:schema刷新模型缓存,否则旧配置仍生效
确认 delete_time 字段定义合规
数据库字段是硬性门槛,错一点就全链路失效:
- 字段类型必须是
DATETIME或TIMESTAMP -
Null列必须为YES(即允许 NULL) -
Default值必须为NULL,不能是'1970-01-01'或CURRENT_TIMESTAMP - 执行
DESCRIBE user;验证;若不合规,用以下语句修复:ALTER TABLE `user` MODIFY COLUMN `delete_time` DATETIME NULL DEFAULT NULL;
确保操作走的是模型层,不是 Db 直连
软删除是模型拦截机制,绕过模型等于绕过软删:
立即学习“PHP免费学习笔记(深入)”;
- ✅ 正确调用:
UserModel::destroy(123)、$user->delete()、UserModel::destroy([1,2,3]) - ❌ 错误调用:
Db::name('user')->delete(123)、UserModel::where('id', 123)->delete()——这些直连 Db,直接物理删除 - 查软删数据需显式调用:
UserModel::onlyTrashed()->select()或UserModel::withTrashed()->select()
分页与关联查询的特殊处理
这两个场景最容易踩坑:
-
withTrashed()必须放在链式调用最前端,例如:UserModel::withTrashed()->where('status', 1)->paginate(10);写成where()->withTrashed()会失效 - 分页的
count()不继承withTrashed(),需手动传total参数避免总数不准 - 关联查询(如
with('posts'))不会自动继承主模型的软删状态;要在关联方法里加->withTrashed(),或用闭包:with(['posts' => function($q) { $q->withTrashed(); }])



















