insert_batch()不能自动去重,必须配合唯一索引+原生SQL(如INSERT ON DUPLICATE KEY UPDATE)实现跳过或更新;需确保email等字段建有UNIQUE约束,手动拼SQL并分块事务执行,避免脏数据与超时。

insert_batch() 不能去重,update_batch() 不支持多条件,Excel 导入重复数据直接报错或写入脏数据——这是 CodeIgniter 批量导入最常踩的坑。必须手动拼 INSERT ... ON DUPLICATE KEY UPDATE,并确保唯一索引、分块事务、strict mode 关闭三者齐备,否则第二次导入大概率失败。
为什么 insert_batch() 导入 Excel 会重复或报错
它只是把二维数组拆成 N 条单 INSERT 串行执行,不带任何冲突处理逻辑:
- 没建
UNIQUE(email)约束时,ON DUPLICATE KEY UPDATE根本不触发,重复数据照插 - 已有重复值却强行加唯一索引,
ALTER TABLE ... ADD UNIQUE(email)直接失败,得先DELETE或GROUP BY去重 - 字段名含关键字(如
order、group)必须写成'`order`' => 'desc',用field_bind()无效 - 返回值是总影响行数(
int),失败只返FALSE,错误藏在$this->db->error()里,不查就以为超时
怎么安全实现“导入即去重”(MySQL 场景)
靠 $this->db->query() 拼原生 SQL,别指望框架封装:
- 唯一依据字段(如
email)必须已建UNIQUE INDEX,检查用SHOW CREATE TABLE excel_files - SQL 中用
VALUES(col)引用待插入值,比硬写变量名更安全,例如username = VALUES(username) - 只想跳过重复?把更新部分写成
id = id(假设id是主键),避免NULL写入非空字段 -
NULL值必须字面量写NULL,不能加引号;字符串一律用$this->db->escape(),别用addslashes()
$sql = "INSERT INTO excel_files (username, email, address) VALUES ";
$values = [];
foreach ($data as $row) {
$values[] = sprintf(
"(%s, %s, %s)",
$this->db->escape($row['username']),
$this->db->escape($row['email']),
$this->db->escape($row['address'])
);
}
$sql .= implode(',', $values);
$sql .= " ON DUPLICATE KEY UPDATE username = VALUES(username), address = VALUES(address);";
$this->db->query($sql);
大批量导入必做的三件事:分块、事务、关 strict mode
500 行以上不处理,PHP 超时、MySQL 报 max_allowed_packet、整批因空字符串插 NOT NULL 字段而静默失败:
- 分块大小建议 ≤ 500 行,每块单独拼 SQL +
$this->db->transStart()/transComplete() - CI3:数据库配置加
'stricton' => FALSE;CI4:在.env的 DSN 加strict=0,例如database.default.DSN="mysql:host=localhost;dbname=test;charset=utf8mb4;strict=0" - 务必确认没调过
$this->db->transOff(),否则事务开关失效,白包 - 导出 Excel 本身不卡,但导入时若表有触发器或外键约束,性能会断崖下跌,测试前先
SET FOREIGN_KEY_CHECKS=0(记得恢复)
update_batch() 为什么总“更新不上”或“乱更新”
它只认你传的「匹配字段」(第三个参数),完全忽略之前所有 where() 链式调用:
- 数组结构必须严格对齐:
[['id'=>1,'name'=>'A'],['id'=>2,'name'=>'B']],混用['id'=>1]和['uid'=>2]会导致第二条静默跳过 - 匹配字段(如
id)必须是数据库真实列名,且类型匹配——传字符串'1'更新 INT 主键会失败 - CI4 中受
$allowedFields白名单限制,漏配字段会被过滤,更新无效;临时调试可用$model->skipValidation()->update_batch(),但上线前必须补全 - 真要按
(pro_id, color_id)联合更新?update_batch()无能为力,只能手拼INSERT ... ON DUPLICATE KEY UPDATE或显式循环 + 事务


















