saveAll()用于逐条判断新增或更新,需严格匹配主键字段名并触发模型事件;update()是原生SQL批量更新,性能高但绕过模型逻辑、不触发钩子,且必须带WHERE条件防全表误改。

saveAll() 和 update() 是 ThinkPHP 批量更新的两个主力方法,但它们适用场景完全不同。用错一个,轻则字段乱写、钩子不触发,重则全表清空、锁表超时。
用 saveAll() 更新已有记录,主键必须对得上
它本质是「逐条判断新增 or 更新」:有主键值 → 走 UPDATE;没主键或主键不存在 → 走 INSERT。常见失效原因不是代码写错,而是主键字段名不一致。
- 查模型类里的
$pk = 'id',前端传的必须是['id' => 123],传['user_id' => 123]就会当成新记录插入 - 数据里不能漏主键 ——
[['id'=>1,'status'=>1], ['status'=>2]]中第二条因无id,直接变成 INSERT - 想触发
before_update等模型事件,saveAll()是唯一能走通的批量方式;update()静态调用不走任何模型钩子 - 开启严格模式可提前暴露问题:
Db::setConfig(['strict' => true]),缺失主键时直接报错,不静默插入
用 Model::update() 或 Db::table()->update() 批量改状态
这是真正下推到 SQL 的批量更新,性能高、不查库,但完全绕过模型逻辑。适合「把所有 status=0 的订单改成 1」这类简单条件更新。
-
Order::update(['status' => 1], ['status' => 0])是正确写法;错写成$order->where(...)->update(...)会无效(实例方法只作用于当前对象) -
Db::table('order')->whereIn('id', $ids)->update(['status' => 1])更快,但不触发事件、不处理时间戳、不校验字段合法性 - 务必带
where——Db::table('user')->update(['status'=>0])会清空全表status,ThinkPHP 6+ 默认不拦截空条件 - 开发期建议加全局 SQL 监听,拦截无 WHERE 的 UPDATE:
Db::listen(function ($sql) { if (stripos($sql, 'UPDATE') !== false && !preg_match('/WHERE/i', $sql)) { throw new Exception('Missing WHERE in UPDATE'); } });
只想更新几个字段,别让其他字段被覆盖
ThinkPHP 默认会把模型所有非空属性塞进 SET 子句,哪怕你只改了 status,name、created_at 也可能被写进去。
- 用
allowField()显式限定:$user->allowField(['status', 'updated_at'])->save(['status' => 2]) - 时间戳字段默认强制写入,要关掉得用开关参数:
save(['status' => 2], ['update_time' => false]),注意这不是传值,是传布尔开关 - 字段含点号(如
profile.age)不支持allowField(),只能切到原生Db::table()->where()->update() - 想做
score = score + 10这类计算更新,必须用['score' => ['exp', 'score + 10']]或Db::raw('score + 10')
大批量 ID 更新卡死?先看是不是数据库锁住了
不是 PHP 慢,是 MySQL 在执行 UPDATE ... WHERE id IN (1,2,3,...) 时,遇到 ID 不连续或数量过大(比如上万),可能升级为表锁或触发间隙锁,阻塞其他请求。
立即学习“PHP免费学习笔记(深入)”;
- 别拼字符串 IN 条件:
where('id', 'in', implode(',', $ids))有 SQL 注入风险;必须用whereIn('id', $ids) - 确保
id字段有索引,否则全表扫描 + 锁表,比慢还危险 - 拆分批次处理:
array_chunk($ids, 500)分批,每批独立事务,避免单次锁太久 - 如果条件是时间范围(如
created_time < '2025-01-01'),更要确认该字段已建索引
Model::update() 还在等 afterUpdate 触发,或者传了 user_id 却忘了模型主键是 id。这些地方没有运行时报错,只有数据行为异常,排查起来反而最耗时间。



















