update() 直接按条件执行 sql 更新,不依赖模型、不触发验证,适合多数场景;save() 基于模型实例“先查后改”,需谨慎使用以防误增或验证拦截。

save 和 update 都能更新数据,但行为逻辑完全不同:前者依赖模型实例状态,后者是纯条件驱动的 SQL 更新。选错会导致“看似执行了,实际没改”或“验证失败却静默跳过”。
用 update() 直接按条件更新(推荐多数场景)
这是最贴近 SQL 原意的方式,不依赖模型加载、不触发自动验证(除非你显式加),适合表单提交后直接更新指定字段。
-
Db::name('user')->where('id', 1)->update(['name' => 'thinkphp']):生成标准 UPDATE 语句,返回影响行数(0 表示没匹配到或值未变) - 如果数据数组里含主键(如
['id'=>1, 'name'=>'xxx']),可省略where():Db::name('user')->update(['id'=>1, 'name'=>'xxx']) - 要更新字段为表达式(比如
score = score + 1),必须用Db::raw():'score' => Db::raw('score + 1');旧写法['exp', 'score + 1']在 V5.1.7+ 已弃用 - 批量更新多条记录?只要
where()条件能命中多行,update()天然支持——比如where('status', 0)->update(['status' => 1])
用 save() 基于模型实例更新(需谨慎)
它本质是“先查后改”,必须基于一个已存在的模型对象调用,否则会变成新增(除非你显式声明 isUpdate(true))。
- 正确姿势:
$user = User::get(1); $user->name = 'new name'; $user->save();—— 这会用主键id=1做 WHERE 条件 - 错误姿势:
(new User())->save(['id'=>1, 'name'=>'xxx'])—— 默认当新增处理,除非加->isUpdate(true) - 验证会拦截:即使数据合法,若模型定义了
validate且字段未通过校验(如长度不足),save()返回false,且getError()才能看到具体原因 - 字段过滤风险:
allowField(true)是安全习惯,否则用户可能传入非法字段(如is_admin)并被写入
别踩这些坑:返回值和空更新
update() 和 save() 都可能返回 0,但这不等于“失败”——它只代表“没有数据被实际修改”。比如原值就是 name='thinkphp',再设成一样,SQL 影响行为 0。
- 不要用
if ($res)判断成功,而应检查是否=== false(失败)或>= 0(执行完成) -
setField()看似简单,但它只支持单字段或数组字段更新,且不能混用表达式和普通值(比如不能一边'name'=>'xxx'一边'score'=>Db::raw(...)) -
saveAll()批量更新时,每个子数组必须带主键(如['id'=>1, 'name'=>'a']),否则会当作新增插入
真正容易被忽略的是:更新操作是否该走验证,取决于业务语义。管理员后台改用户邮箱,通常要重验格式;而点击“标记已读”这种无输入操作,用 update() 绕过验证更干净。别让一个方法包打天下。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











