You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于外键使用Eloquent批量插入更新多行的最优方案

最优实现方案:批量UPSERT(插入或更新)

首先必须先做一个关键准备:给你的answers表添加唯一组合索引,因为我们需要靠customer_id和question_id的组合来判断记录是否存在。你可以通过迁移文件或者直接执行SQL来创建:

// 迁移文件示例
public function up()
{
    Schema::table('answers', function (Blueprint $table) {
        $table->unique(['customer_id', 'question_id']);
    });
}

或者直接执行SQL:

ALTER TABLE answers ADD UNIQUE INDEX idx_customer_question (customer_id, question_id);

方案1:Laravel 8+ 原生支持的 upsert 方法(最推荐)

从Laravel 8开始,Eloquent原生提供了upsert方法,完美适配你的需求——一条SQL完成批量的“存在则更新,不存在则插入”,完全不需要循环处理,性能拉满。

具体实现代码如下:

use App\Models\Answer;

// 解析请求数据
$requestData = request()->validate([
    'customer_id' => 'required|integer',
    'answer' => 'required|array',
]);

$customerId = $requestData['customer_id'];
$answers = $requestData['answer'];

// 转换为upsert需要的格式:每个元素是包含三个字段的数组
$upsertData = collect($answers)->map(function ($value, $questionId) use ($customerId) {
    return [
        'customer_id' => $customerId,
        'question_id' => $questionId,
        'value' => $value,
    ];
})->toArray();

// 执行批量UPSERT
Answer::upsert(
    $upsertData,
    ['customer_id', 'question_id'], // 用来判断重复的唯一键组合
    ['value'] // 当记录存在时,需要更新的字段
);

这个方法的底层就是利用MySQL的INSERT ... ON DUPLICATE KEY UPDATE语法,所有操作在单条SQL中完成,不管你有多少条答案,性能都不会有问题。


方案2:兼容Laravel 7及以下版本(原生SQL实现)

如果你的Laravel版本低于8.x,无法使用upsert方法,可以直接通过DB门面构造原生的批量UPSERT语句:

use Illuminate\Support\Facades\DB;

// 同样先解析请求数据,得到$customerId和$answers数组

// 构造插入字段和值
$columns = ['customer_id', 'question_id', 'value'];
$bindings = [];
$valuePlaceholders = [];

foreach ($answers as $questionId => $value) {
    $valuePlaceholders[] = '(?, ?, ?)';
    $bindings[] = $customerId;
    $bindings[] = $questionId;
    $bindings[] = $value;
}

// 构造SQL语句
$sql = sprintf(
    "INSERT INTO answers (%s) VALUES %s ON DUPLICATE KEY UPDATE value = VALUES(value)",
    implode(', ', $columns),
    implode(', ', $valuePlaceholders)
);

// 执行SQL(参数绑定更安全,避免SQL注入)
DB::statement($sql, $bindings);

第三方库方案(非必需)

其实上面的官方方案已经完全满足需求了,但如果你需要更复杂的批量操作逻辑(比如更新多个字段、自定义更新规则),可以考虑使用第三方包,比如yadakhov/insert-on-duplicate-key。不过个人建议优先用官方原生方法,避免引入额外依赖。

举个该包的使用示例(先通过Composer安装):

composer require yadakhov/insert-on-duplicate-key

然后使用:

use Yadakhov\InsertOnDuplicateKey;

$insert = new InsertOnDuplicateKey();
$insert->table('answers')
       ->columns(['customer_id', 'question_id', 'value'])
       ->values($upsertData)
       ->onDuplicateKeyUpdate(['value' => 'VALUES(value)'])
       ->execute();

内容的提问来源于stack exchange,提问作者Michael Chandra Lrc

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.11 09:24:37