最稳妥的更新方式是用 save() 方法配合主键,它会触发模型事件、自动处理时间戳、支持验证和修改器;而 update() 和 db::table()->where()->update() 易绕过这些机制导致隐患。

ThinkPHP6.0 更新数据最稳妥的方式是用 save() 方法配合主键,而不是直接调用 update() 或裸写 Db::table()->where()->update() —— 后两者容易绕过模型事件、自动时间戳和验证逻辑。
用 save() 更新单条记录(推荐)
这是模型层最标准的更新路径,会触发 updating/updated 事件、自动处理 update_time、支持验证和修改器。
- 必须确保模型已设置主键(
$pk),且数据中包含该主键值(如id) - 只传需要更新的字段,未传字段不会被清空或覆盖
- 若主键不在数据中,
save()会转为插入(除非显式指定isUpdate)
$user = new User(); $user->id = 123; $user->nickname = 'newname'; $user->score = $user->score + 10; // 支持表达式(需开启 <code>auto_write_timestamp</code> 或手动处理) $user->save(); // 自动识别为更新
用 Db::table() 批量更新(绕过模型)
适合后台脚本、定时任务或不需要模型逻辑的场景;但不会触发任何模型钩子,也不校验字段合法性。
-
where()条件必须明确,否则可能误更新整张表(线上务必加limit(1)测试) - 时间字段需手动赋值,例如
'update_time' => date('Y-m-d H:i:s') - 数字字段自增要写成
['score' => Db::raw('score + 10')],不能直接写表达式
Db::table('user')->where('status', 0)->update([
'status' => 1,
'update_time' => date('Y-m-d H:i:s')
]);
update() 方法的两个坑
这个方法常被误用:它既不是模型方法也不是查询构造器方法,而是 Query 类的静态快捷入口,行为容易混淆。
- 调用
User::update(['id'=>1, 'name'=>'x'])时,如果id是主键且存在,才更新;否则静默失败(不报错) - 它不走模型的
save()流程,跳过验证、事件、修改器,但会尝试写入update_time(取决于配置) - 批量更新必须显式传
where数组,例如User::update(['status'=>1], ['id'=>['in',[1,2,3]]]),否则只更新第一条匹配
软删除后还能更新吗?
能,但默认 update() 和 save() 都会自动追加 delete_time IS NULL 条件 —— 这意味着已软删除的记录无法被常规更新命中。
- 要更新软删除数据,得先用
withTrashed():User::withTrashed()->where('id', 1)->save(['note'=>'restored']) - 或者临时关闭软删除:
User::withoutGlobalScope('SoftDelete')->where('id', 1)->update([...]) - 注意:软删除字段本身(
delete_time)不能通过普通save()清空,需用restore()或原生 SQL
真正容易出问题的是混合使用模型方法和 Db 类操作,比如在一个事务里先 $model->save() 再 Db::table()->where()->update(),后者会绕过模型缓存和事件,导致状态不一致。更新逻辑一旦复杂,就老老实实走模型 save(),别贪快去“优化”掉一层封装。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











