ThinkPHP 8.0中delete()直接物理删除数据行,需配合主键或where条件;destroy()支持模型事件和软删除,Db类操作绕过软删除逻辑,事务中须统一连接避免部分提交。

delete() 方法直接删除数据行
ThinkPHP 8.0 中,delete() 是最常用的物理删除方式,调用后会真正从数据库中移除记录。它必须配合主键或明确的查询条件使用,否则会报错或误删。
常见错误现象:Call to undefined method think\db\Query::delete() —— 这说明你是在 Query 对象(比如 Db::table() 或 model::where())上直接调用了 delete(),但没指定主键值或没触发执行。
- 若已知主键值(如 ID=5),直接传入:
UsersModel::delete(5)或Db::name('users')->delete(5) - 若需按条件删除,必须用
where()+delete()组合:Db::name('users')->where('status', 0)->delete() - 批量删除多条时,传数组:
UserModel::delete([1, 2, 3]),前提是主键字段名是id;否则需显式指定:UserModel::destroy([1,2,3], true)
destroy() 方法做模型级安全删除
destroy() 是模型类提供的封装方法,比裸用 delete() 更安全,会自动触发事件、验证和软删除判断(如果启用了软删除)。
使用场景:你希望删除前执行钩子(如 beforeDelete)、检查关联数据、或统一走模型生命周期管理时,优先选 destroy()。
立即学习“PHP免费学习笔记(深入)”;
- 单条删除:
UserModel::destroy(123),会查出该记录再删除,支持事件 - 条件删除:
UserModel::destroy(['status' => 'draft'], true),第二个参数true表示强制按条件删(不查出数据),性能更好但跳过部分钩子 - 注意:如果模型启用了软删除(
use SoftDeleteTrait),destroy()默认只更新delete_time字段,不会真删 —— 这是设计行为,不是 bug
软删除:delete_time 字段怎么生效
ThinkPHP 8.0 的软删除依赖模型中定义的 delete_time 字段,默认为 datetime null 类型。它不靠中间件或全局配置,而是由模型 trait 和 destroy() / delete() 的调用路径决定是否启用。
容易踩的坑:Db::name('users')->where(...)->delete() 永远是物理删除,完全绕过软删除逻辑;只有模型方法(destroy()、delete() 静态调用、实例 $user->delete())才会检查 delete_time 是否存在。
- 确保模型类 use
think\model\concern\SoftDelete,并设置protected $deleteTime = 'delete_time'; - 查询时默认自动过滤已软删除数据,如需查全部,加
withTrashed():UserModel::withTrashed()->find(123) - 真正物理删除软删数据,用
force(true):UserModel::destroy(123, true)->force(true)
事务中删除失败导致部分提交
多个删除操作放在事务里时,最容易忽略的是:不同模型或 Db 查询混用,导致事务上下文丢失。例如在事务块内,用 Db::delete() 删表 A,再用 UserModel::destroy() 删用户,后者可能因未显式绑定连接而脱离事务。
性能与兼容性影响:TP8 默认使用 PDO,事务对 MySQL 有效,但 SQLite 或 SQL Server 下行为略有差异;另外,destroy() 在事务中查出数据再删,比 Db::delete() 多一次查询,高并发下要注意。
- 统一用 Db 类操作:所有删操作都走
Db::transaction(function () { ... })内的Db::name()->where()->delete() - 若必须用模型,确保模型配置了
'connection' => 'default',且事务开启后所有模型操作共享同一连接 - 别在事务里混用
Db::execute('DELETE FROM...')原生语句 —— 它不参与 TP 的事务管理,除非你手动用 PDO::exec 并确认连接一致
软删除字段名、事务连接绑定、模型与 Db 删除路径的差异,这三点一旦设错,删着删着就发现数据没影了或者根本没删掉 —— 不是框架问题,是调用链路没对齐。



















