ThinkPHP软删失效需检查配置、字段类型及方法使用:模型启用SoftDelete并设$deleteTime;delete_time用int或datetime类型;批量软删用destroy()而非delete();查已删数据用withTrashed();恢复用restore()并注意业务一致性。

ThinkPHP 软删字段没生效?先确认 soft_delete 配置和字段类型
软删不是调用 delete() 就自动触发的,得让模型知道“哪些字段管软删”。常见现象是:执行了 where()->delete(),数据库记录直接没了,或者根本没变 —— 很可能 delete_time 字段没被识别。
- 模型类里必须启用软删除:
use SoftDelete;+protected $deleteTime = 'delete_time';(字段名要和数据库一致) -
delete_time字段类型推荐int(10) UNSIGNED或datetime,别用varchar,否则where('delete_time', null)会失效 - 如果用了自定义软删字段(比如
is_deleted),得额外配protected $defaultSoftDelete = 1;和protected $softDelete = true;
批量软删必须用 destroy(),别用 delete()
delete() 是硬删(哪怕开了软删),而真正批量软删靠的是 destroy()。它会把符合条件的记录统一打上删除标记,而不是删数据行。
- 正确写法:
UserModel::destroy(['status' => 0, 'id' => ['in', [1,2,3]]]); - 错误写法:
UserModel::where(['status' => 0])->delete();→ 这会绕过软删逻辑,直接物理删除 - 注意:如果传的是数组条件,
destroy()默认走主键查询再逐条软删;想跳过主键校验、直接 SQL 更新,得加参数:destroy($where, true)(第二个参数为true表示强制批量更新)
按条件软删后查不到数据?检查全局作用域是否干扰
软删后默认不查已删记录,这是通过全局作用域自动加 where('delete_time', null) 实现的。但如果你手动写了 where('delete_time', null) 或用了 withTrashed() / onlyTrashed(),行为就变了。
- 想查包括已软删的数据:
UserModel::withTrashed()->select(); - 只查已软删的:
UserModel::onlyTrashed()->select(); - 如果模型里重写了
baseScope()或用了scope方法,可能覆盖了软删作用域,导致条件失效 - 调试时可打印 SQL:
echo UserModel::where(['id' => 1])->buildSql();,看生成的 WHERE 里有没有delete_time IS NULL
软删后恢复数据用 restore(),但注意主键约束和关联逻辑
restore() 不是万能回滚键,它只清空 delete_time 字段,其他字段原样不动。如果业务依赖软删前的状态(比如缓存、关联表状态),得自己补逻辑。
立即学习“PHP免费学习笔记(深入)”;
- 单条恢复:
UserModel::withTrashed()->find(123)->restore(); - 批量恢复:
UserModel::withTrashed()->where('delete_time', '', null)->restore(); - 如果模型有唯一索引(如
email),恢复时得确保该值未被新数据占用,否则抛出Integrity constraint violation - 关联模型不会自动恢复,比如订单软删了,用户恢复后订单仍不可见,得单独处理
destroy() 和 delete() 的差别,几乎决定了你是删数据还是删日志。



















