本文详解php批量向数据库写入大量数据时在20–50条记录处中断的根本原因——并非数据库连接或sql语法问题,而是外部api(如ssb统计数据接口)触发了严格的请求频率限制(http 429),并提供延迟控制、批处理与错误恢复等专业级解决方案。
在使用PHP脚本从外部API批量获取数据并写入MySQL数据库时,开发者常遇到一种“看似随机却高度规律”的失败现象:当每轮仅插入1–2列字段时脚本全程稳定;但一旦扩展至10列以上(如本例中更新11个年份的人口字段),脚本总在第20–50次循环后静默终止或报错。问题表面指向数据库,实则根源在于外部API的服务端限流机制。
? 根本原因:API请求被限频(HTTP 429)
通过复现该脚本并注入调试逻辑(如 curl_error($curl)),可明确捕获关键错误响应:
{"error":"429 - Too many requests in too short timeframe. Please try again later."}
这表明目标API(本例为挪威统计局 SSB 的 /api/v0/no/table/06913/ 接口)实施了严格的速率限制(Rate Limiting)。连续发起约60次cURL请求后即触发熔断,后续请求直接返回HTTP 429状态码,而原始脚本未检查 curl_exec() 返回值或HTTP状态码,导致 $resp 为空或非法JSON,进而引发 json_decode() 失败、数组访问越界(如 $test[‘value’][0] 报Notice),最终使 mysqli_query() 执行空SQL或含非法值的SQL,造成静默中断或数据库报错。
⚠️ 注意:mysqli_error($conn) 中的 $conn 变量名错误(应为 $tilkobling),且未检查 curl_exec() 是否成功,这是常见调试盲区。
✅ 解决方案一:添加请求节流(简单有效)
最直接的修复是在每次API调用后加入可控延迟,避免触达限流阈值:
立即学习“PHP免费学习笔记(深入)”;
// 在 curl_close($curl); 后添加 usleep(500000); // 暂停500毫秒(0.5秒) // 或更保守地:sleep(1); // 暂停1秒
✅ 优点:实现简单,立即生效。
⚠️ 注意:需根据实际限流策略调整间隔(如每分钟60次 → 平均间隔≥1秒);生产环境建议动态探测限流头(如 Retry-After)。
✅ 解决方案二:批量请求 + 批量更新(推荐)
更优解是减少HTTP请求数量。观察SSB API文档可知,其支持单次请求聚合多区域数据。例如,将 “values”: [“K_0101”] 改为 “values”: [“K_0101”, “K_0102”, “K_0103”],即可一次获取多个市镇数据。改造后:
// 构建批量区域列表(每批最多10个,避免单请求过大)
$batchSize = 10;
$kommuneBatch = array_slice($kommune_api_data['containeditems'], $kom, $batchSize);
$regionValues = [];
foreach ($kommuneBatch as $item) {
if ($item['codevalue'] !== '2211') {
$regionValues[] = 'K_' . $item['codevalue'];
}
}
// 在JSON payload中替换Region values
"values": $regionValues
随后解析响应时,按顺序匹配各市镇数据,并使用 INSERT … ON DUPLICATE KEY UPDATE 或 REPLACE INTO 批量写入: