CodeIgniter 批量插入需事务控制+分块+环境调优三者配合,单独用 insert_batch() 无法避免超时;CI3/CI4 必须显式开启事务、每批1000–3000行、关闭strict mode、字段关键字加反引号。

CodeIgniter 框架里用 insert_batch() 或 insertBatch() 做循环批量插入,本身不等于“自动避超时”。真正避免超时、锁等待、内存溢出和 MySQL 拒绝连接,靠的是事务控制 + 分块 + 环境调优三者配合。单独调用一次 insert_batch(),数据量一大照样卡死或报错。
必须显式开启并控制事务边界
CI3 和 CI4 默认每条 insert 都 auto-commit,500 条 = 500 次刷盘 + 500 次锁持有。不包事务,insert_batch() 只是把慢操作从 PHP 循环搬进框架内部,没本质提升。
- CI3 写法:
$this->db->transStart();<br> $this->db->insert_batch('table', $chunk);<br> $this->db->transComplete(); - CI4 写法:
$this->db->transBegin();<br> $this->db->table('table')->insertBatch($chunk);<br> if ($this->db->transStatus() === false) {<br> $this->db->transRollback();<br> } else {<br> $this->db->transCommit();<br> } - 别依赖隐式事务:检查当前连接
SELECT @@autocommit,必要时开头加$this->db->query('SET autocommit = 0');
每次只处理 1000–3000 行,按需分块
不是数据越多越好。单批太大,会触发 max_allowed_packet 超限、InnoDB 日志写满(innodb_log_file_size 不足)、锁等待超时(innodb_lock_wait_timeout=50s 默认)。
- PHP 层手动切块:
$chunks = array_chunk($all_data, 2000);<br> foreach ($chunks as $chunk) { /* 执行带事务的 insert_batch */ } - 每块执行完可加微小延迟(如
usleep(5000)),缓解锁队列堆积和 CPU 抢占 - 字段多或含长文本时,适当缩小单批行数(比如降到 800–1200)
关 strict mode,防空字符串等整批失败
MySQL 开启 strict mode 后,往 NOT NULL 字段插空字符串、零日期、非法数字等,会导致整批 insert_batch() 直接返回 FALSE,错误藏在 $this->db->error() 里,不查就以为是超时。
- 连接初始化时执行:
$this->db->query("SET SESSION sql_mode = ''");
或更精准地去掉 STRICT_TRANS_TABLES:$this->db->query("SET SESSION sql_mode = (SELECT REPLACE(@@sql_mode,'STRICT_TRANS_TABLES',''))"); - 同时确认字段值已过滤:NULL 值保留为
null(不是字符串'null'),空字符串转为null或默认值
字段含关键字?手动加反引号
CI3 的 insert_batch() 不自动给字段名加反引号,遇到 order、group、key 这类关键字直接语法错误。CI4 的 insertBatch() 也存在同样问题。
- 写数组时显式加反引号:
[ '`order`' => 'desc', '`group`' => 'admin' ] - 不要指望
field_bind()或其他 AR 方法能自动处理——它对 insert_batch 无效 - 建议建表时避开 MySQL 保留字,长期看比每次手动加更省心

















