thinkphp软删除失效源于模型配置、数据库字段、调用方式三者未对齐:需正确引入softdelete trait、配置$deletetime与$usesoftdelete、delete_time字段须为datetime/timestamp且nullable default null、必须通过模型方法调用而非db类直删。

检查模型是否真正启用 SoftDelete
只写 use SoftDelete; 不够,必须同时满足:
- 导入正确命名空间:use think\model\concern\SoftDelete;
- 类内声明 trait:use SoftDelete;
- 显式指定字段名:protected $deleteTime = 'delete_time';(即使用默认名也建议写上)
- TP6.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;
确保删除和查询走的是模型层
软删除是模型拦截机制,绕过模型就等于绕过软删:
- ✅ 正确调用: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() 必须置于链式调用最前端,且不被全局作用域覆盖:
- ❌ 错误:User::where('status', 1)->withTrashed()->paginate(10)
- ✅ 正确:User::withTrashed()->where('status', 1)->paginate(10)
- 关联查询(如
with('user'))默认不继承主模型软删状态,需在关联方法中加 ->withTrashed(),或用闭包预载:
->with(['user' => function ($q) { $q->withTrashed(); }]) - paginate() 的 count 查询不继承软删状态,总数不准时可手动传 total:
User::withTrashed()->paginate(10, false, ['total' => User::withTrashed()->count()])
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











