update() 返回值即影响行数,为整数;返回0可能因新旧值相同、软删除过滤、全局作用域拦截、wherein参数非法或事务未提交。

直接用 update() 返回值就行,别套 count() 或其他函数——它本来就是整数,不是集合。
为什么 update() 返回 0 却实际改了数据?
常见于 WHERE 条件匹配到记录,但新旧值完全一致。MySQL 和 PostgreSQL 都会跳过更新(affected rows = 0),哪怕 SQL 执行成功。这不是 Laravel 的 bug,是数据库行为。
- 检查字段值是否真有变化:比如
'status' => 1传进去,但数据库里已经是1 - 软删除模型默认排除已删除记录,
where('deleted_at', null)是隐式条件;若想包含,得显式加withTrashed() - 全局作用域(如租户隔离)可能悄悄过滤掉本该命中的行,用
DB::enableQueryLog()看最终生成的 SQL
whereIn + update() 影响行数少于预期?
根本原因是 whereIn('id', $ids) 中的 $ids 有非法值(字符串、null、重复 ID、数据库里不存在的 ID),导致部分参数被 MySQL 忽略或转换失败。
- 确保
$ids是纯整型数组:array_map('intval', $ids)或collect($ids)->map->intval()->all() - MySQL 对
IN子句参数数量有限制(默认 65535,但受max_allowed_packet实际约束),超 5000 项建议分块处理 - 执行前先查存在性:
DB::table('orders')->whereIn('id', $ids)->count()对比count($ids),差值即“丢失 ID”数量
upsert() 返回影响行数不直观?
upsert() 底层是 INSERT ... ON DUPLICATE KEY UPDATE,返回值是「插入 + 更新」总行数,无法单独拆出更新了几行。业务上若需精确区分,得换策略。
- 不要依赖
upsert()返回值做“是否更新成功”的判断,它不反映冲突是否发生 - 需要精确计数时,改用两步法:先
whereIn('id', $ids)->get(['id'])拿出真实存在的 ID 列表,再对这个列表调用update() - SQLite 用户注意:
upsert()在 3.24+ 才支持,旧版本会抛BadMethodCallException,上线前必须验证环境
最易被忽略的是:事务中执行 update() 后没 commit 就去查,或者用了读已提交(READ COMMITTED)隔离级别却在另一个连接里立刻查——影响行数没错,但你看到的数据还没刷出去。











