软删除字段 deleted_at 必须是 datetime 类型,MySQL 用 DATETIME/TIMESTAMP,SQLite 用 TEXT 存 ISO 格式并配置 type;onlyTrashed() 加 WHERE deleted_at IS NOT NULL,withTrashed() 仅移除全局过滤;查时间范围须用 whereTime() 而非 whereBetween();restore() 依赖 deleted_at 字段真实值、模型配置及查询上下文三者对齐。

软删除字段 deleted_at 必须是 datetime 类型
ThinkPHP 的软删除依赖数据库字段的类型判断是否“已删除”,如果把 deleted_at 设为 int(时间戳)或 varchar,whereTime('deleted_at', 'neq', null) 会失效,查询时直接忽略该条件。MySQL 中必须用 DATETIME 或 TIMESTAMP;SQLite 可用 TEXT 存 ISO 格式(如 '2024-05-20 10:30:00'),但需确保模型配置 type 匹配。
常见错误现象:withTrashed() 能查出数据,但 onlyTrashed() 返回空,或 whereTime('deleted_at', 'between', [...]) 不生效 —— 先检查字段类型和模型中是否显式声明了类型:
protected $type = [
'deleted_at' => 'datetime'
];
onlyTrashed() 和 withTrashed() 的实际行为差异
这两个方法本质是给查询加了不同 WHERE 条件,不是“开关式”状态切换:
-
onlyTrashed()→ 自动追加WHERE deleted_at IS NOT NULL -
withTrashed()→ 移除全局软删除作用域(即不加WHERE deleted_at IS NULL),但也不会主动查被删数据,要配合whereNotNull('deleted_at')才能拿到软删记录 - 单独调用
withTrashed()后再链式写where('id', 123),结果取决于该记录是否被软删:若deleted_at为NULL就能查到,否则查不到 —— 它只是“不过滤”,不是“强制包含”
按软删除时间范围查询要用 whereTime(),别用 whereBetween()
whereBetween('deleted_at', ['2024-01-01', '2024-06-01']) 在 MySQL 下可能因隐式类型转换失败(比如字段是 TIMESTAMP 但传字符串),且无法兼容 SQLite。正确做法是用 ThinkPHP 内置的 whereTime(),它会自动处理不同数据库的时间格式:
// 查 3 天内被软删除的用户
UserModel::onlyTrashed()
->whereTime('deleted_at', '>=', '-3 days')
->select();
// 查指定日期区间(注意:值必须是可被 parse_time() 解析的格式)
UserModel::onlyTrashed()
->whereTime('deleted_at', 'between', ['2024-05-01', '2024-05-31'])
->select();
关键点:whereTime() 底层调用的是数据库原生时间函数(如 MySQL 的 DATE()),比手动拼字符串更安全;传入 '-3 days' 这类相对表达式时,TP 会在 PHP 层先解析成绝对时间再传入 SQL。
恢复软删除记录时 restore() 不会清空 deleted_at 字段?
默认情况下,$model->restore() 确实只是把 deleted_at 设为 NULL,但如果你在模型里重写了 deleteTime 配置,比如设成了 'delete_time' 或启用了自动时间戳(autoWriteTimestamp),就可能导致 restore() 没反应或报错。确认以下三点:
- 模型中未自定义
deleteTime属性(保持默认'deleted_at') -
protected $autoWriteTimestamp = true;时,确保deleteTime与时间戳字段不冲突 - 执行
restore()前,该模型实例必须是从onlyTrashed()或带whereNotNull('deleted_at')查询出来的,否则 TP 不认为它是“已软删状态”,调用无效
最稳妥的恢复方式其实是显式赋值后保存:
$user = UserModel::onlyTrashed()->find(123); $user->deleted_at = null; $user->save();
软删除不是魔法,所有基于 deleted_at 的逻辑都依赖字段真实值、模型配置、查询上下文三者严格对齐 —— 少一个,whereTime 就可能查不到,restore 就可能静默失败。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











