
Laravel 提供了 wasChanged() 方法,可在 save() 执行后准确判断模型属性是否真正发生变更,从而实现“仅当数据被修改时才记录日志”的精准控制,避免因 isDirty() 重置导致的误判。
laravel 提供了 `waschanged()` 方法,可在 `save()` 执行后准确判断模型属性是否真正发生变更,从而实现“仅当数据被修改时才记录日志”的精准控制,避免因 `isdirty()` 重置导致的误判。
在 Laravel Eloquent 中,isDirty() 是判断模型当前内存状态是否与原始加载值存在差异的常用方法,但它会在调用 save() 后自动清空脏数据标记——这意味着你无法在保存之后再通过 isDirty() 检测变更。这正是许多开发者(包括你)遇到的核心痛点:日志逻辑必须放在 save() 之后以确保数据库写入成功,但此时 isDirty() 已失效。
幸运的是,Laravel 自 v5.8 起就内置了专为此场景设计的方法:wasChanged()。它不依赖当前内存脏状态,而是记录上一次成功保存操作中实际更新的字段,并在整个请求生命周期内保持可用。其行为严格满足你的需求:
- ✅ 在
save()或update()执行后立即可用; - ✅ 返回
true当且仅当本次保存确实向数据库提交了至少一个字段变更; - ✅ 支持细粒度校验,如
$model->wasChanged('email'); - ✅ 与事务兼容,即使后续回滚,
wasChanged()的返回值仍反映该次save()的实际执行意图(注意:日志应置于事务提交后以保证语义一致性)。
正确用法示例
// 假设 $user 是已加载的 Eloquent 模型
$user->name = 'Alice';
$user->email = 'alice@example.com';
// 执行保存(可能触发 UPDATE SQL)
$success = $user->save();
if ($success && $user->wasChanged()) {
\Log::info('User updated', [
'id' => $user->id,
'changed_fields' => $user->getChanges(), // 获取具体变更字段及新值
'updated_at' => $user->updated_at,
]);
}?
getChanges()是wasChanged()的补充方法,返回一个关联数组(如['name' => 'Alice', 'email' => 'alice@example.com']),非常适合结构化日志或审计追踪。
注意事项与最佳实践
-
不要在
creating/updating等模型事件中依赖wasChanged():它仅在saved事件之后才被设置,应在saved或updated事件回调中使用,或像示例中一样在save()后同步调用; -
批量更新需谨慎:
Model::where(...)->update(...)不会触发模型事件,也不会设置wasChanged(),此类场景需改用集合遍历 + 单模型save(),或手动比对原始值; -
结合事务增强可靠性:若业务要求“日志与数据强一致”,建议将
save()和日志写入包裹在同一数据库事务中(Laravel 的DB::transaction()),确保二者原子性; -
性能无负担:
wasChanged()仅读取内部changes属性(由save()内部填充),无额外查询开销。
综上,wasChanged() 是 Laravel 官方为解决“保存后判定变更”这一高频需求而提供的简洁、可靠、语义明确的原生方案——无需自定义状态缓存,无需侵入事件系统,一行代码即可替代手动保存前快照的冗余逻辑。


















