ThinkPHP导入Excel支持断点续传:通过动态startRow分块读取、缓存最后行号、事务控制及状态标记实现。每批处理后更新缓存(commit后),失败时查缓存或数据库excel_row字段恢复,避免用MAX(id)推算。

ThinkPHP导入Excel时遇到网络中断或页面刷新,必须能从中断行继续解析入库,而不是重头开始——这要求系统记录已处理行号、跳过已入库数据、保持事务一致性。
启用分块读取并记录断点位置
使用 PhpSpreadsheet 的 getRowIterator($startRow, $chunkSize) 按固定行数分批拉取,每批处理完立即写入数据库并缓存当前最大行号。
调用 $reader->getWorksheetIterator() 获取第一个工作表后,用 $worksheet->getRowIterator(2, 500) 从第2行(跳过标题)开始,每次读500行;【$startRow 必须动态传入,不能硬写成2】,否则断点失效。
将当前 chunk 最后一行号存入缓存:cache('import_' . $fileId . '_last_row', $endRow),键名带文件唯一标识,避免多任务冲突。
恢复导入时跳过已处理行
方法一:读取缓存值,作为下一次 getRowIterator() 的起始行参数。
方法二:若缓存丢失,查数据库最新插入记录的行号,加1后作为起点;但需确保该字段明确记录原始 Excel 行号(如加 excel_row 字段)。
注意:不要用 MAX(id) 推算行号——自增ID可能因删除、回滚不连续,会导致漏行或重复。
合并断点与事务控制
第一步:开启事务 Db::transaction(function () use ($dataChunk) { ... });,保证单次 chunk 全部写入或全部回滚。
第二步:执行 Db::insertAll($dataChunk) 后,立即更新缓存行号;【缓存更新必须在事务 commit 之后】,否则事务失败时缓存已变,下次启动会跳过未入库数据。
第三步:事务成功后调用 cache('import_' . $fileId . '_status', 'running') 标记任务进行中,防止并发重复触发。
清理与状态判断
导入完成时,删掉缓存键 import_{$fileId}_last_row 和 import_{$fileId}_status。
前端轮询接口检查 cache('import_' . $fileId . '_status') 值:为 null 表示已完成,为 running 表示进行中,为 failed 表示异常中断可续传。
若检测到 failed 状态,且缓存中存在 last_row,则返回该值供前端显示“已导入 X 行,可继续”。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











