ThinkPHP 8.1 模型软删除失效本质是模型、数据库、调用三者未对齐:需同时满足启用SoftDelete trait、配置$deleteTime与$useSoftDelete、delete_time字段类型为DATETIME/TIMESTAMP且允许NULL默认NULL、操作必须通过模型层而非Db直连,并正确使用onlyTrashed()/withTrashed()。

ThinkPHP 8.1 模型软删除失效,本质是模型、数据库、调用三者没对齐。不是框架坏了,而是配置漏了关键环节——只要一个点没配对,delete() 就变真删,restore() 也静默失败。
检查模型是否真正启用了 SoftDelete
只写 use SoftDelete; 不够,必须同时满足:
- 导入正确命名空间:
use think\model\concern\SoftDelete; - 类内声明 trait:
use SoftDelete; - 显式指定软删字段:
protected $deleteTime = 'delete_time';(即使用默认名也建议写上) - ThinkPHP 8.1 中仍需开关控制:
protected $useSoftDelete = true; - 改完后执行
php think optimize:schema刷新模型缓存,否则旧配置继续生效
验证 delete_time 字段是否合规
这是硬性门槛,错一点就全链路失效:
- 字段类型必须是
DATETIME或TIMESTAMP(不推荐用INT,除非明确配置$type) -
Null列必须为YES(即允许 NULL) -
Default值必须为NULL,不能是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() 和关联查询的常见陷阱
这两个场景最容易误判为“失效”:
-
withTrashed()必须放在链式调用最前端,例如:UserModel::withTrashed()->where('status', 1)->select();写成where()->withTrashed()会失效 - 关联查询(如
with('posts'))不会继承主模型的软删状态;需在关联方法里加->withTrashed(),或用闭包:with(['posts' => function($q) { $q->withTrashed(); }]) - 用
buildSql(true)查看生成 SQL,确认delete_time IS NULL条件是否被移除或替换



















