laravel 的 update() 方法本身不接受 where 条件,正确做法是链式调用 where() 后再调用 update();直接 user::update([...]) 会无条件更新全表,极其危险;返回值为受影响行数(int),不触发事件或访问器。

update() 方法里直接写 where 条件
Laravel 的 update() 本身不接受条件参数,但 Eloquent 和 Query Builder 都支持链式调用 where() 后再 update(),这才是标准做法。别试图把条件塞进 update() 第一个参数里——那只是要更新的字段数组。
常见错误是写成:User::update(['status' => 'active', 'updated_at' => now()]),这会无条件更新全表,非常危险。
- 正确姿势:用
where()定义条件,再调用update() - 字段值支持原生表达式,比如
DB::raw('view_count + 1') - 返回值是受影响行数(int),不是模型实例,别指望它有事件或访问器触发
// Eloquent 方式
User::where('status', 'pending')
->where('created_at', 'subDays(7))
->update(['status' => 'expired']);
// Query Builder 方式
DB::table('users')
->where('last_login_at', 'subMonths(1))
->update(['is_active' => false]);
需要触发模型事件时必须用 save() + 循环?
不是。想让 updating、updated 等事件生效,又不想查出全部模型再逐个 save()(性能灾难),可以用 chunkById() 分批处理。
注意:Eloquent 的 update() 绕过模型生命周期,事件、强制转换、访问器全不触发;而 save() 触发完整流程,但代价是 N+1 查询和内存占用。
- 数据量小(get() 再
each->save() - 数据量大:用
chunkById()+update()批量更新字段,再单独发事件(如广播或队列任务) - 不要用
all()->each(...),容易 OOM
whereRaw / JSON 字段条件怎么写
MySQL 8+ 或 PostgreSQL 处理 JSON 字段时,不能只靠 where('meta->type', 'admin') 这种魔法语法——它在某些版本或驱动下不生效,且无法利用索引。
更可靠的是显式用 whereRaw() 配合数据库原生 JSON 函数,同时注意参数绑定防注入。
- MySQL:
whereRaw("JSON_CONTAINS(meta, ? , '$.roles')", ['["admin"]']) - PostgreSQL:
whereRaw("? @> ?", [DB::raw('meta'), '{"status":"draft"}']) - 避免在
whereRaw()中拼接用户输入,一律用参数占位符
// 安全示例:更新满足 JSON 条件的记录
DB::table('posts')
->whereRaw("meta->>'status' = ?", ['archived'])
->whereRaw("meta->>'priority' > ?", ['5'])
->update(['is_flagged' => true]);
update() 返回 0 却没报错?检查这些点
返回 0 只代表“没匹配到符合条件的行”,不等于失败。很多人误以为是 SQL 报错或连接异常,其实只是条件太严或数据已变更。
- 先确认
where()条件是否真能命中数据(可临时换成count()测试) - 检查字段名是否拼错,尤其是带前缀的表(如
users.idvsid) - MySQL strict mode 下,若更新值超出字段长度(如 varchar(10) 存 15 字符),可能静默截断并返回 0 行影响
- 事务中执行后未
commit(),其他连接查不到变化,但本连接的update()仍返回正确行数
真正该警惕的是抛出 QueryException,比如字段不存在、类型不匹配、锁超时——这些才需要 try/catch。











