0

0

深入理解 Eloquent update() 方法:避免意外更新脏数据

霞舞

霞舞

发布时间:2025-07-28 21:42:01

|

731人浏览过

|

来源于php中文网

原创

深入理解 Eloquent update() 方法:避免意外更新脏数据

本文旨在深入探讨 Eloquent ORM 中 update() 方法的行为特性,特别是其在更新指定字段的同时,可能意外更新模型实例上已修改(脏)但未明确传入 update() 方法的属性。我们将分析其内部工作机制,并提供一种推荐的解决方案,即通过直接使用查询构建器进行更新,以确保仅更新目标字段,同时讲解如何保持模型实例与数据库同步。

Eloquent update() 方法的默认行为解析

在使用 eloquent orm 进行数据更新时,开发者常会遇到一个不符合直觉的现象:当通过模型实例调用 update() 方法并传入特定字段进行更新时,模型实例上在此之前被修改但未传入 update() 方法的“脏”属性也可能一并被更新到数据库中。

考虑以下代码示例:

$user = User::find(1); // 从数据库加载用户

$user->is_admin = 1; // 修改了 is_admin 属性,但尚未保存

$user->update(['first_name' => 'Alex']); // 意图只更新 first_name
// 结果:is_admin 字段也可能被更新为 1!

为什么会发生这种情况?原因在于 Eloquent Model 类的 update() 方法的内部实现。根据其源代码定义,update() 方法首先会调用 fill() 方法将传入的属性填充到模型实例中,然后紧接着调用 save() 方法。

/**
 * Update the model in the database.
 *
 * @param  array  $attributes
 * @param  array  $options
 * @return bool
 */
public function update(array $attributes = [], array $options = [])
{
    if (! $this->exists) {
        return false;
    }

    return $this->fill($attributes)->save($options);
}

save() 方法的职责是保存模型实例的所有“脏”属性(即与从数据库加载时或上次保存后相比发生变化的属性)到数据库。因此,当 update() 方法被调用时,它不仅会保存传入 attributes 数组中的字段,还会将模型实例中所有在 update() 调用之前被修改过的其他属性一并保存。在上述示例中,$user->is_admin = 1; 这行代码已经将 is_admin 标记为“脏”属性,因此在 update(['first_name' => 'Alex']) 执行时,is_admin 也会被 save() 方法更新到数据库。

解决方案:使用查询构建器进行精确更新

为了避免这种意外的副作用,确保只更新指定的字段,推荐的方法是绕过模型实例的 save() 行为,直接使用 Eloquent 的查询构建器(Query Builder)进行更新。这样可以精确控制哪些字段会被修改。

$user = User::find(1); // 从数据库加载用户

$user->is_admin = 1; // 此时模型实例的 is_admin 属性已被修改

// 使用查询构建器直接更新数据库,只影响指定的字段
User::whereKey($user->getKey())->update(['first_name' => 'Alex']);

// 此时数据库中只有 first_name 被更新,is_admin 保持不变(除非之前就是1)
// 但请注意,内存中的 $user 实例的 first_name 仍是旧值,is_admin 仍是 1

重要注意事项:模型实例与数据库同步

Fotor AI Face Generator
Fotor AI Face Generator

Fotor 平台的在线 AI 头像生成器

下载

当使用 User::whereKey($user->getKey())->update(...) 这种方式进行更新时,数据库中的记录会被修改,但内存中 $user 变量所引用的模型实例并不会自动更新以反映这些变化。如果后续操作依赖于 $user 实例的最新状态,你需要手动同步它。

有两种主要的同步方式:

  1. 手动更新模型实例的属性: 如果你知道哪些字段被更新了,可以直接设置模型实例的属性。同时,为了确保模型实例的“脏”状态正确,可以调用 setOriginalAttribute() 来更新其原始属性值。

    $user = User::find(1);
    $user->is_admin = 1;
    
    User::whereKey($user->getKey())->update(['first_name' => 'Alex']);
    
    // 手动更新内存中的模型实例
    $user->first_name = 'Alex';
    // 可选:更新原始属性以清除其“脏”状态,防止后续意外保存
    $user->setOriginalAttribute('first_name', 'Alex');
    
    // 此时 $user->first_name 已经是 'Alex'
  2. 刷新模型实例: 如果你不确定哪些字段被更新了,或者更新逻辑复杂,可以使用 refresh() 方法重新从数据库加载模型实例的最新数据。这会产生一次额外的数据库查询。

    $user = User::find(1);
    $user->is_admin = 1;
    
    User::whereKey($user->getKey())->update(['first_name' => 'Alex']);
    
    // 重新从数据库加载最新数据到模型实例
    $user->refresh();
    
    // 此时 $user->first_name 已经是 'Alex',is_admin 保持数据库中的原值

    请注意,虽然 refresh() 会产生额外查询,但在某些复杂场景下,它可能是最稳健的同步方式。

总结

Eloquent 的 update() 方法在模型实例上调用时,会将其内部所有已修改(脏)的属性一并保存。如果需要精确控制只更新传入的特定字段,而不触及模型实例上其他已修改的属性,则应使用查询构建器(例如 Model::whereKey($id)->update([...]))进行更新。在使用查询构建器更新后,务必记住手动同步内存中的模型实例,或者通过 refresh() 方法重新加载以确保数据一致性。理解这些细微差别对于编写健壮和可预测的 Eloquent 代码至关重要。

相关专题

更多
数据库三范式
数据库三范式

数据库三范式是一种设计规范,用于规范化关系型数据库中的数据结构,它通过消除冗余数据、提高数据库性能和数据一致性,提供了一种有效的数据库设计方法。本专题提供数据库三范式相关的文章、下载和课程。

336

2023.06.29

如何删除数据库
如何删除数据库

删除数据库是指在MySQL中完全移除一个数据库及其所包含的所有数据和结构,作用包括:1、释放存储空间;2、确保数据的安全性;3、提高数据库的整体性能,加速查询和操作的执行速度。尽管删除数据库具有一些好处,但在执行任何删除操作之前,务必谨慎操作,并备份重要的数据。删除数据库将永久性地删除所有相关数据和结构,无法回滚。

2068

2023.08.14

vb怎么连接数据库
vb怎么连接数据库

在VB中,连接数据库通常使用ADO(ActiveX 数据对象)或 DAO(Data Access Objects)这两个技术来实现:1、引入ADO库;2、创建ADO连接对象;3、配置连接字符串;4、打开连接;5、执行SQL语句;6、处理查询结果;7、关闭连接即可。

346

2023.08.31

MySQL恢复数据库
MySQL恢复数据库

MySQL恢复数据库的方法有使用物理备份恢复、使用逻辑备份恢复、使用二进制日志恢复和使用数据库复制进行恢复等。本专题为大家提供MySQL数据库相关的文章、下载、课程内容,供大家免费下载体验。

251

2023.09.05

vb中怎么连接access数据库
vb中怎么连接access数据库

vb中连接access数据库的步骤包括引用必要的命名空间、创建连接字符串、创建连接对象、打开连接、执行SQL语句和关闭连接。本专题为大家提供连接access数据库相关的文章、下载、课程内容,供大家免费下载体验。

321

2023.10.09

数据库对象名无效怎么解决
数据库对象名无效怎么解决

数据库对象名无效解决办法:1、检查使用的对象名是否正确,确保没有拼写错误;2、检查数据库中是否已存在具有相同名称的对象,如果是,请更改对象名为一个不同的名称,然后重新创建;3、确保在连接数据库时使用了正确的用户名、密码和数据库名称;4、尝试重启数据库服务,然后再次尝试创建或使用对象;5、尝试更新驱动程序,然后再次尝试创建或使用对象。

402

2023.10.16

vb连接access数据库的方法
vb连接access数据库的方法

vb连接access数据库方法:1、使用ADO连接,首先导入System.Data.OleDb模块,然后定义一个连接字符串,接着创建一个OleDbConnection对象并使用Open() 方法打开连接;2、使用DAO连接,首先导入 Microsoft.Jet.OLEDB模块,然后定义一个连接字符串,接着创建一个JetConnection对象并使用Open()方法打开连接即可。

374

2023.10.16

vb连接数据库的方法
vb连接数据库的方法

vb连接数据库的方法有使用ADO对象库、使用OLEDB数据提供程序、使用ODBC数据源等。详细介绍:1、使用ADO对象库方法,ADO是一种用于访问数据库的COM组件,可以通过ADO连接数据库并执行SQL语句。可以使用ADODB.Connection对象来建立与数据库的连接,然后使用ADODB.Recordset对象来执行查询和操作数据;2、使用OLEDB数据提供程序方法等等。

218

2023.10.19

php源码安装教程大全
php源码安装教程大全

本专题整合了php源码安装教程,阅读专题下面的文章了解更多详细内容。

150

2025.12.31

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
PHP自制框架
PHP自制框架

共8课时 | 0.6万人学习

PHP面向对象基础课程(更新中)
PHP面向对象基础课程(更新中)

共12课时 | 0.6万人学习

AI绘画教程
AI绘画教程

共2课时 | 0.2万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号