如何在laravel-excel中分别统计更新与插入的行数
Laravel Excel WithUpserts 场景下分别统计插入、更新行数实现方案
Laravel Excel 底层的 Upsert 能力直接调用 Eloquent/QueryBuilder 的原生upsert方法,数据库层面不会直接返回区分插入、更新的行数统计,需要通过批次预处理的方式自行计数,实现步骤如下:
第一步:在导入类中初始化计数属性
在实现了WithUpserts接口的导入类中,定义两个公共属性分别存储插入、更新的累计行数,初始值设为0:namespace App\Imports; use Maatwebsite\Excel\Concerns\WithUpserts; use App\Models\YourTargetModel; class BusinessDataImport implements WithUpserts { // 累计插入行数 public int $insertedCount = 0; // 累计更新行数 public int $updatedCount = 0; // 原有方法保持不变 public function uniqueBy() { // 返回你配置的upsert唯一判断字段,支持单字段/多字段数组 return 'sku'; } public function model(array $row) { return new YourTargetModel([ // 原有字段映射逻辑 ]); } }第二步:接入批量插入能力,注册批次前置事件做统计
实现WithBatchInserts、WithEvents接口,在每一批数据写入数据库前,提前比对当前批次的唯一键和数据库已存在数据,分别累加两类行数:use Maatwebsite\Excel\Concerns\WithBatchInserts; use Maatwebsite\Excel\Concerns\WithEvents; use Maatwebsite\Excel\Events\BeforeBatchImport; use Illuminate\Support\Collection; class BusinessDataImport implements WithUpserts, WithBatchInserts, WithEvents { public int $insertedCount = 0; public int $updatedCount = 0; // 配置单批次写入行数,根据服务器性能调整即可 public function batchSize(): int { return 200; } // 注册事件回调 public function registerEvents(): array { return [ BeforeBatchImport::class => function (BeforeBatchImport $event) { $batchRows = $event->getDelegate()->getRows(); if (!$batchRows instanceof Collection || $batchRows->isEmpty()) { return; } $uniqueColumns = (array)$this->uniqueBy(); // 统计当前批次有效数据行数 $validRowCount = $batchRows->filter(function ($row) use ($uniqueColumns) { foreach ($uniqueColumns as $col) { if (empty($row->{$col})) return false; } return true; })->count(); // 查询当前批次中已存在于数据库的记录数,即本批次待更新行数 $existedQuery = $this->model(); foreach ($uniqueColumns as $col) { $colValues = $batchRows->pluck($col)->filter()->unique()->toArray(); $existedQuery = $existedQuery->whereIn($col, $colValues); } $existedCount = $existedQuery->count(); // 累加计数 $this->updatedCount += $existedCount; $this->insertedCount += $validRowCount - $existedCount; }, ]; } // 原有uniqueBy、model方法保持不变 public function uniqueBy() { return 'sku'; } public function model(array $row) { return new YourTargetModel([]); } }第三步:导入执行完成后读取统计值
实例化导入类执行导入操作后,直接访问类上的两个公共属性就能拿到最终计数:$import = new BusinessDataImport(); \Maatwebsite\Excel\Facades\Excel::import($import, request()->file('import_file')); // 直接取数使用 $insertTotal = $import->insertedCount; $updateTotal = $import->updatedCount;
注意事项:
- 该统计方案逻辑和Upsert的判断规则完全对齐,无并发写入场景下统计准确率100%;如果导入同时存在其他并发写入同表的操作,建议导入时加表锁避免计数偏差。
- 不要直接用数据库返回的Upsert影响行数做统计:以MySQL为例,Upsert操作返回的影响行数规则为「新增行记1、更新行字段有变更记2、更新行无字段变更记0」,无法直接准确映射实际插入、更新的行数。
- 如果使用复合唯一键做Upsert判断,上述代码已经做了兼容,不需要额外调整逻辑。
内容的提问来源于stack exchange,提问作者Rahmouni Rabii
相关产品推荐
相关产品推荐

