codeigniter原生不支持自动去重批量更新;update_batch()仅支持单字段where(如id),无法按email等非主键字段更新,必须手动拼写insert on duplicate key update并确保email建有unique索引、分块事务执行且关闭strict mode。

CodeIgniter 本身没有提供“自动去重 + 批量更新”的封装方法,update_batch() 不支持多条件 WHERE,insert_batch() 也不处理冲突——想靠框架默认方法安全批量更新数组数据,基本走不通。
为什么 update_batch() 不能按 email 更新?
它只接受一个字段做 WHERE 条件,比如 id;但业务中常要按 email 或 username 更新,而这两个字段通常不是主键。传 ['email' => 'a@b.com'] 当 key,框架会硬拼成 WHERE id = 'a@b.com',直接错表或无效果。
-
update_batch()的 WHERE 字段名写死在底层,无法动态指定 - 传入的二维数组必须带主键字段(如
id),否则返回 FALSE 且不报具体错误 - 即使你把
email当作主键设进模型,$this->primaryKey = 'email',也得确保 DB 层真有该字段索引,否则性能极差
手写原生 SQL 实现 email 为依据的批量更新
真正可控的方式是拼 INSERT ... ON DUPLICATE KEY UPDATE,前提是 email 已建 UNIQUE INDEX。别绕开这步,否则整条逻辑无效。
- 先确认索引存在:
SHOW INDEX FROM users WHERE Key_name = 'email_unique' - 字段含关键字(如
order、group)必须用反引号包裹:`order` - NULL 值必须字面量写
NULL,不能写成'NULL'或空字符串 - 所有字符串值必须过
$this->db->escape(),别用addslashes()
示例片段:
$sql = "INSERT INTO users (email, name, status) VALUES ";
$values = [];
foreach ($data as $row) {
$values[] = sprintf(
"(%s, %s, %s)",
$this->db->escape($row['email']),
$this->db->escape($row['name']),
$row['status'] === null ? 'NULL' : $this->db->escape($row['status'])
);
}
$sql .= implode(',', $values);
$sql .= " ON DUPLICATE KEY UPDATE name = VALUES(name), status = VALUES(status);";
$this->db->query($sql);
大批量时必须分块 + 关 strict mode
500 行以上不处理,MySQL 容易报 max_allowed_packet 或因空字符串插 NOT NULL 字段静默失败。strict mode 一开,整批就崩,且错误信息只说“Query error”,不指哪行哪列。
- CI3:数据库配置加
'stricton' => FALSE,或连接后执行$this->db->query('SET sql_mode = ""') - CI4:在
.env中改 DSN,加strict=0,例如database.default.DSN="mysql:host=localhost;dbname=test;charset=utf8mb4;strict=0" - 每块 ≤ 500 行,用
$this->db->transStart()/transComplete()包裹,避免部分成功部分失败 - 务必检查
$this->db->error(),update_batch()失败只返FALSE,不查就等于没报错
最易被忽略的是:唯一索引没建好,或建了但已有重复值,ALTER 会直接失败;还有就是事务没真正生效——调过 $this->db->transOff() 却忘了恢复,包了也白包。











