
在日常的 Web 开发中,我们经常会遇到需要批量处理数据库记录的场景。比如,从外部系统同步用户数据,或者在导入 Excel 文件时更新现有记录并插入新记录。对于 Laravel 开发者来说,你可能会第一时间想到使用 Eloquent 提供的 updateOrCreate() 方法。然而,当你面对成百上千甚至上万条数据时,问题就来了。
updateOrCreate() 方法固然方便,但它本质上是对单条记录进行操作:先查询是否存在,再决定更新还是插入。这意味着,如果你有 N 条数据需要处理,它将执行至少 N 条数据库查询(N 次 SELECT + N 次 INSERT/UPDATE),这被称为 N+1 查询问题。当数据量庞大时,这种模式会导致:
updateOrCreate() 简洁,但为了批量操作而将其放入循环中,总感觉不是最优解。我曾在一个数据同步项目中深受其害。每天需要同步数万条用户数据,使用 updateOrCreate() 后,同步过程耗时数小时,且经常导致数据库连接超时。我尝试过手动拼接 SQL 语句,但那不仅繁琐易错,还破坏了 Eloquent 的便利性。难道就没有一种既高效又符合 Laravel 风格的解决方案吗?
yadakhov/insert-on-duplicate-key
正当我为此苦恼时,我发现了 yadakhov/insert-on-duplicate-key 这个 Composer 包。它完美地解决了我的困境,提供了一种在 Laravel 中优雅地实现 MySQL INSERT ... ON DUPLICATE KEY UPDATE 批量操作的方案。
INSERT ... ON DUPLICATE KEY UPDATE?这是 MySQL 数据库特有的一个强大功能。它允许你在尝试插入多条记录时,如果遇到主键或唯一索引冲突,则不报错,而是执行指定的更新操作。这样,我们就能在一个 SQL 语句中完成“插入或更新”的逻辑,将 N 次数据库操作优化为仅仅 1 次!
使用 yadakhov/insert-on-duplicate-key 非常简单,只需通过 Composer 安装即可:
<code class="bash">composer require yadakhov/insert-on-duplicate-key</code>
安装完成后,你需要在你的 Eloquent 模型中使用它提供的 InsertOnDuplicateKey trait。
<pre class="brush:php;toolbar:false;">use Illuminate\Database\Eloquent\Model;
use Yadakhov\InsertOnDuplicateKey;
class User extends Model
{
// 引入这个 trait,即可拥有批量操作的能力
use InsertOnDuplicateKey;
protected $fillable = ['id', 'email', 'name', 'heritage']; // 确保你的模型有 fillable 字段
}现在,你的 User 模型就具备了强大的批量操作能力。
insertOnDuplicateKey)这是最常用的功能。它接受一个包含多个数组的数组,每个内层数组代表一条记录的数据。
<pre class="brush:php;toolbar:false;">use Carbon\Carbon; // 如果你需要处理时间戳
$users = [
['id' => 1, 'email' => 'user1@example.com', 'name' => 'User One', 'created_at' => Carbon::now(), 'updated_at' => Carbon::now()],
['id' => 2, 'email' => 'user2@example.com', 'name' => 'User Two', 'created_at' => Carbon::now(), 'updated_at' => Carbon::now()],
['id' => 3, 'email' => 'user3@example.com', 'name' => 'User Three', 'created_at' => Carbon::now(), 'updated_at' => Carbon::now()],
];
// 默认情况下,如果发生冲突,所有字段都会被更新(除了主键)
User::insertOnDuplicateKey($users);
/*
会生成类似这样的 SQL 语句:
INSERT INTO `users`(`id`,`email`,`name`,`created_at`,`updated_at`) VALUES
(1,'user1@example.com','User One',...), (2,'user2@example.com','User Two',...), (3,'user3@example.com','User Three',...)
ON DUPLICATE KEY UPDATE `id` = VALUES(`id`), `email` = VALUES(`email`), `name` = VALUES(`name`), `created_at` = VALUES(`created_at`), `updated_at` = VALUES(`updated_at`)
*/重要提示: 传递给 insertOnDuplicateKey 的数据数组,其内部键的顺序必须保持一致。因为底层实现会使用 array_values() 来获取值。
如果你只想更新部分字段,可以作为第二个参数传递:
<pre class="brush:php;toolbar:false;">// 如果发生冲突,只更新 email 字段 User::insertOnDuplicateKey($users, ['email']); /* SQL 语句将变为: ... ON DUPLICATE KEY UPDATE `email` = VALUES(`email`) */
更高级的用法是,你可以使用 DB::raw() 来进行复杂的更新操作,例如累加一个数字字段:
<pre class="brush:php;toolbar:false;">use Illuminate\Support\Facades\DB;
$usersWithHeritage = [
['id' => 1, 'name' => 'User One', 'heritage' => 1000, 'created_at' => Carbon::now(), 'updated_at' => Carbon::now()],
['id' => 2, 'name' => 'User Two', 'heritage' => 2000, 'created_at' => Carbon::now(), 'updated_at' => Carbon::now()],
];
// 如果 id 冲突,则将 heritage 字段累加
User::insertOnDuplicateKey($usersWithHeritage, ['heritage' => DB::raw('`heritage` + VALUES(`heritage`)')]);
/*
SQL 语句将变为:
... ON DUPLICATE KEY UPDATE `heritage` = `heritage` + VALUES(`heritage`)
*/请注意,created_at 和 updated_at 字段不会自动处理。你需要手动在数据数组中提供它们的值,就像上面的示例一样。
insertIgnore)如果你只希望插入新记录,而忽略任何与现有记录的冲突,可以使用 insertIgnore:
<pre class="brush:php;toolbar:false;">User::insertIgnore($users); /* 会生成类似这样的 SQL 语句: INSERT IGNORE INTO `users`(`id`,`email`,`name`) VALUES (...) */
replace)REPLACE INTO 语句会删除旧记录并插入新记录(如果存在冲突)。
<pre class="brush:php;toolbar:false;">User::replace($users); /* 会生成类似这样的 SQL 语句: REPLACE INTO `users`(`id`,`email`,`name`) VALUES (...) */
使用 yadakhov/insert-on-duplicate-key 后,我项目的同步时间从数小时缩短到了几分钟,数据库负载也显著降低。它的优势显而易见:
yadakhov/insert-on-duplicate-key 是 Laravel 开发者处理 MySQL 批量数据同步和更新的利器。它通过利用数据库本身的优化能力,彻底解决了传统方法中 N+1 查询带来的性能瓶颈。如果你正在为 Laravel 项目中大数据量的插入或更新操作效率低下而烦恼,那么这个 Composer 包绝对值得你一试。它将让你的代码更高效、更健壮,同时保持 Laravel 开发的优雅与便捷。
以上就是Laravel大数据批量操作慢如蜗牛?yadakhov/insert-on-duplicate-key助你轻松解决,效率飙升!的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号