
laravel 中使用 update() 方法时若绕过 eloquent 实例直接调用静态查询(如 stationery::where(…)->update()),将跳过模型事件、访问器、强制类型转换及批量赋值保护机制,导致数据看似“成功更新”实则未生效——尤其当模型启用了 $guarded 或 $fillable 时。
laravel 中使用 update() 方法时若绕过 eloquent 实例直接调用静态查询(如 stationery::where(…)->update()),将跳过模型事件、访问器、强制类型转换及批量赋值保护机制,导致数据看似“成功更新”实则未生效——尤其当模型启用了 $guarded 或 $fillable 时。
在 laravel 的资源控制器中,update 方法常配合路由模型绑定(Route Model Binding)使用,例如签名 update(Request $request, Stationery $stationery)。此时 $stationery 已是一个已从数据库加载的 Eloquent 模型实例,具备完整的生命周期钩子、属性转换、以及对 $fillable / $guarded 的校验能力。
而原代码中:
Stationery::where('id', $stationery->id)->update($validated);
采用的是 Query Builder 风格的批量更新:它直接生成 sql UPDATE … SET … WHERE 语句,完全绕过 Eloquent 实例,因此:
- ✅ 跳过 $guarded 和 $fillable 的字段白名单/黑名单检查(看似“能写”,实则隐患);
- ❌ 不触发 updating / updated 事件;
- ❌ 忽略 cast 类型转换(如 ‘harga’ => ‘Integer’ 不生效);
- ❌ 不调用 set*Attribute 访问器(如自动格式化价格、清理描述);
- ❌ 不更新 updated_at 时间戳(除非显式包含);
- ❌ 若模型启用了 SoftDeletes,也不会影响 deleted_at 状态。
✅ 正确做法是复用已绑定的模型实例,调用其 update() 实例方法:
public function update(Request $request, Stationery $stationery) { $validated = $request->validate([ 'category_id' => 'required|exists:categories,id', 'nama' => 'required|string|max:255', 'satuan' => 'nullable|string|max:50', 'harga' => 'required|numeric|min:0', 'keterangan' => 'nullable|string', ]); // ✅ 正确:通过模型实例更新 → 触发完整 Eloquent 生命周期 $stationery->update($validated); return redirect('/barang/pakaihabis')->with('success', 'Data Berhasil Diubah!!'); }
⚠️ 注意事项:
- 确保模型中已正确定义 $fillable(推荐)或保持 $guarded = [‘id’] 合理 —— 但无论哪种方式,实例 update() 都会严格遵循该策略;
- 若需自定义保存逻辑(如记录修改人、审计日志),应在模型中监听 updating 事件,或重写 save() 方法;
- 避免混用 static::update() 与 instance->update():前者为底层 SQL 批量操作,后者为面向对象的业务级更新;
- 开发阶段可启用 DB::enableQueryLog() 并 dd(DB::getQueryLog()) 对比两种写法生成的 SQL,直观理解差异。
总结:Laravel 的优雅在于“约定优于配置”,路由模型绑定提供的实例不是占位符,而是承载业务逻辑的核心载体。善用 ->update() 实例方法,既是修复数据不更新问题的关键,更是保障应用可维护性与扩展性的最佳实践。