在thinkphp 7中启用软删除需三者对齐:数据库添加nullable delete_time字段、模型启用softdelete trait并配置$usesoftdelete=true、操作必须通过模型方法(如destroy或$model->delete),否则将触发物理删除或逻辑失效。

在ThinkPHP 7中启用模型软删除功能,必须让数据库字段、模型配置、操作方式三者完全对齐,缺一不可——否则看似调用了delete(),实际却是物理删除,或查询时数据凭空消失。
数据库添加delete_time字段
第一步:执行SQL语句为对应数据表添加软删除标记字段。
ALTER TABLE user ADD delete_time DATETIME NULL DEFAULT NULL;
⚠️ 字段名必须为delete_time(TP7硬编码识别,默认不支持自定义),类型必须是DATETIME或TIMESTAMP,且绝对不可设为NOT NULL。如果已有表结构含delete_time NOT NULL DEFAULT CURRENT_TIMESTAMP,新插入记录会立刻被判定为“已删除”,导致数据刚入库就查不到。
第二步:修改表结构后,【必须清空runtime/cache/目录】。框架会缓存表结构,不清缓存会导致模型仍按旧结构解析字段,软删除逻辑完全不触发。
模型类启用SoftDelete trait
方法一:基础启用(推荐用于单模型)
在模型文件顶部引入trait:
use think\model\concern\SoftDelete;
在类定义中声明并显式开启:
use SoftDelete;
protected $useSoftDelete = true;
protected $deleteTime = 'delete_time'; // 即使是默认名也建议写明
方法二:时间戳冲突规避(关键!)
若模型启用了自动时间戳($autoWriteTimestamp = true),【切勿将delete_time加入$createTime或$updateTime数组】。否则新增记录时该字段会被自动写入当前时间,等同于“创建即删除”。正确做法是只保留$createTime和$updateTime,让delete_time保持NULL,仅在调用delete()时由SoftDelete逻辑写入。
方法三:整型时间戳支持(仅当数据库字段为BIGINT)
若数据库中delete_time实际存的是时间戳整数(如1721589300),需在模型中声明类型:
protected $type = ['delete_time' => 'integer'];
否则框架内部比对失败,whereNotNull('delete_time')永远不生效,软删除形同虚设。
执行软删除与查询控制
① 软删除操作必须走模型方法:
UserModel::destroy(123) → 触发软删除,update delete_time = NOW()
$user = UserModel::find(123); $user->delete(); → 同样软删
❌ 【Db::name('user')->delete(123)会直接物理删除】,完全绕过模型层,SoftDelete trait毫无作用。
② 查询默认过滤已删数据:
UserModel::select() → 自动附加WHERE delete_time IS NULL,只返回未删记录
③ 查全部(含已删):
UserModel::withTrashed()->select()
④ 只查已删记录:
UserModel::onlyTrashed()->select()
⑤ 恢复单条记录:
$user = UserModel::onlyTrashed()->find(123); $user->restore();
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











