thinkphp cli批量导入数据需绕过web限制、控制内存与事务、确保结构可靠:设set_time_limit(0)、ini_set('memory_limit','-1')、gc_collect_cycles();用phpspreadsheet读取并清洗数据,字段映射+类型转换;分批400条+db::transaction();主键冲突用insert ignore或on duplicate key update原生sql处理。

ThinkPHP后台CLI脚本批量导入数据,核心是绕过Web请求限制、控制内存与事务、确保数据结构可靠。直接用 Db::insertAll() 配合分批 + 事务 + 清洗,不走模型层,效率最高。
CLI环境必须做的基础设置
脚本开头加三行关键配置:
-
取消执行时间限制:
set_time_limit(0),避免10万条数据中途被中断 -
放宽内存限制:
ini_set('memory_limit', '-1')(或设为‘2G’),防止Excel解析或数据组装时OOM -
手动触发垃圾回收:每批插入后调用
gc_collect_cycles(),尤其处理超5万条时能明显稳住内存
Excel读取与数据清洗不能跳过
别把原始Excel数组直接喂给insertAll()——字段错位、空值类型混乱、中文表头和英文字段不匹配,都会导致“Column count doesn’t match value count”报错。
- 用
PhpOffice\PhpSpreadsheet\IOFactory显式指定格式(如createReader('Xlsx')),不依赖自动识别 - 逐行遍历,跳过全空行:
if (array_filter($rowData)) { $data[] = $rowData; } - 做字段映射:把 Excel 表头(如“创建时间”)转成数据库字段名(如
created_at),再统一塞入时间戳:'created_at' => date('Y-m-d H:i:s') - 数值类字段(如状态、是否启用)需强制转整型:
(int)$cellValue,避免MySQL报类型不匹配
分批+事务+安全插入的固定写法
单次插入超过400条易触发 max_allowed_packet 错误,且事务长时间不提交会锁表。必须切片并包裹事务:
- 用
array_chunk($cleanData, 400)拆成每批400条 - 整个流程包在
Db::transaction()闭包里,异常自动回滚 - 复用同一个 Db 实例:
$db = Db::name('user');,不要在循环里反复调用Db::name() - 每批调用
$db->insertAll($chunk),返回值检查非必需,但建议判断是否为false并记录日志
主键冲突和唯一索引怎么处理
insertAll() 不支持 INSERT IGNORE 或 ON DUPLICATE KEY UPDATE,遇到重复就直接报错中断。
- 若只需跳过重复:改用原生SQL:
Db::execute('INSERT IGNORE INTO user (...) VALUES (...), (...)') - 若需“存在则更新”:手写带
ON DUPLICATE KEY UPDATE的语句,用Db::query()执行 - 别在PHP里去重——10万条数据两两比对开销大,且并发下仍可能冲突
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











