单条更新用模型实例的save()触发事件,批量更新用查询构建器update()执行sql;带逻辑更新选updateorcreate()或case when;验证唯一性需忽略当前id,软删除需显式过滤。

直接用 save() 或 update() 就能更新,但选错方法会导致事件不触发、字段被忽略、甚至报 Non-static method ... should not be called statically 错误。
单条模型实例更新:用 save(),别用静态 update()
当你已经拿到一个模型对象(比如通过 find()、first() 获取),就该走实例路径。改属性 + save() 是唯一安全方式。
-
save()会触发updating/updated事件,适合需审计、日志、关联同步的场景 - 它自动识别是 insert 还是 update,依赖模型的
$exists属性 - 如果直接对模型类调用
update()(如User::update([...])),就会报非静态调用错误——因为这个update()是查询构建器方法,不是模型静态方法 -
fill()+save()可以批量赋值,但必须确保字段在$fillable里,否则静默失败
示例:
$user = User::find(123);
if ($user) {
$user->name = '新名字';
$user->email = 'new@example.com';
$user->save(); // ✅ 正确:走实例流程
}
批量条件更新:用查询构建器的 update(),跳过模型层
要一次性改多条记录(比如“把所有 status=pending 的用户设为 active”),必须用 Eloquent 查询构建器链式调用,不能用模型实例。
- 写法是
User::where(...)->update([...]),这里的User::返回的是查询构建器,不是模型类本身 - 它生成一条原生
UPDATESQL,不加载模型、不触发任何模型事件、不校验$fillable - 注意:
updated_at不会自动更新,得手动写进数组里,比如['status' => 'active', 'updated_at' => now()] - 如果条件含数组(如 ID 列表),用
whereIn('id', [1,2,3]),不要手拼 SQL
示例:
User::where('status', 'pending')
->whereIn('id', [101, 102, 105])
->update([
'status' => 'active',
'updated_at' => now()
]); // ✅ 一行 SQL 完成,高效但无事件
带逻辑的批量更新:自己写 CASE WHEN 或用 updateOrCreate()
标准 update() 只支持统一值,没法给每条记录设不同值(比如按 ID 分别设不同 email)。这时有两个现实选择:
- 用原生
CASE WHEN拼 SQL:Laravel 没封装,得手动构造,适合几十条以内、ID 明确的场景;容易出绑定参数错,id字段缺失或类型不一致会直接报错 - 用
updateOrCreate():适用于“有则更新、无则创建”,且判断依据是唯一字段(如email或联合唯一索引);它内部会先firstOrNew()再save(),所以会触发事件,但性能比纯 SQL 差 - 别用
replace into:虽然 Laravel DB 支持,但它本质是删+插,会重置自增 ID、丢失未指定字段值,风险远大于收益
示例(updateOrCreate):
User::updateOrCreate(
['email' => 'a@b.com'], // 查找条件
['name' => 'Alice', 'status' => 'active'] // 不存在时插入,存在时更新这些字段
);
更新时验证唯一性:绕开 unique 规则冲突
用 Validator 验证字段唯一性时,新增和更新共用一套规则,会导致“编辑自己时提示‘用户名已存在’”。解决办法是动态排除当前记录 ID。
- 写法是
'username' => 'required|unique:users,username,' . $user->id,第三个参数是忽略的 ID - 更健壮写法用
Rule::unique('users')->ignore($user),它会自动处理软删除、主键名非id等边界情况 - 如果用的是请求类
FormRequest,在rules()方法里取$this->route('user')或$this->user获取模型实例 - 别漏掉软删除场景:默认
unique不管deleted_at,如需排除已删除记录,得加->whereNull('deleted_at')
示例:
use Illuminate\Validation\Rule;
return [
'email' => [
'required',
Rule::unique('users')->ignore($this->user),
],
];
最易被忽略的是:批量 update() 不走模型生命周期,也不会受 $casts、setXxxAttribute() 访问器影响——它直接写数据库。如果你依赖这些逻辑做数据清洗或格式转换,就得退回到逐条 save(),或者提前在 PHP 层处理好值。这不是性能问题,是语义鸿沟。











