Laravel:从API读取数据去重入库及批量保存避免超时方案
API数据批量入库:去重+超时优化方案
现有代码问题
你当前的store方法用循环调用updateOrCreate,每条数据都单独执行数据库操作,数据量大时不仅速度慢,还容易触发超时;另外updateOrCreate用所有字段作为重复判断条件,完全没必要,应该用唯一标识字段(比如API字段,每个API名称理应唯一)来判断重复。
解决思路
1. 确保无重复记录
- 数据库层面:给
apidata表的API字段添加唯一索引,从根源上杜绝重复数据插入。 - 代码层面:用Laravel的
upsert方法,指定唯一键,批量处理数据——既可以插入新数据,也能按需更新已存在的数据。
2. 避免大量数据超时
- 放弃循环单条操作,改用批量处理逻辑;
- 数据量极大时,可分块处理(比如每50条一批),降低单次数据库操作压力;
- 去掉
set_time_limit这类临时应急方案,从代码逻辑上解决超时问题。
优化后的代码
public function store() { $client = new Client(); $response = $client->request('GET', 'https://api.publicapis.org/entries'); $apidata = json_decode($response->getBody()->getContents(), true); // 整理符合入库要求的数据格式 $records = collect($apidata['entries'])->map(function ($entry) { return [ 'API' => $entry['API'], 'Description' => $entry['Description'], 'Auth' => $entry['Auth'], 'HTTPS' => $entry['HTTPS'], 'Cors' => $entry['Cors'], 'Link' => $entry['Link'], 'Category' => $entry['Category'] ]; })->toArray(); // 批量upsert:指定API为唯一判断键,存在则更新指定字段,不存在则插入 // 前提:数据库的API字段已添加唯一索引 Apidata::upsert( $records, ['API'], // 重复判断的唯一键 ['Description', 'Auth', 'HTTPS', 'Cors', 'Link', 'Category'] // 重复时需要更新的字段 ); return redirect()->back()->with('message', '数据保存成功!'); }
超大数据量额外优化
如果API返回上万条级别的数据,用分块处理进一步降低压力:
collect($apidata['entries'])->chunk(50)->each(function ($chunk) { $chunkData = $chunk->map(function ($entry) { return [ 'API' => $entry['API'], 'Description' => $entry['Description'], 'Auth' => $entry['Auth'], 'HTTPS' => $entry['HTTPS'], 'Cors' => $entry['Cors'], 'Link' => $entry['Link'], 'Category' => $entry['Category'] ]; })->toArray(); Apidata::upsert($chunkData, ['API'], ['Description', 'Auth', 'HTTPS', 'Cors', 'Link', 'Category']); });
数据库唯一索引迁移代码
执行下面的迁移给API字段加唯一索引:
Schema::table('apidata', function (Blueprint $table) { $table->unique('API'); });
内容的提问来源于stack exchange,提问作者S. Radje
相关产品推荐
相关产品推荐

