insertAll本身不支持跳过重复,报1062错误是因执行原生INSERT而非INSERT IGNORE;需改用Db::execute('INSERT IGNORE...')或replaceInto(),并注意数组索引重置与字段缓存更新。

insertAll 报 “Integrity constraint violation: 1062 Duplicate entry”
这不是数据重复逻辑没处理好,是 insertAll 本身不跳过冲突——它走的是原生批量 INSERT INTO,没有 INSERT IGNORE 或 ON DUPLICATE KEY UPDATE 语义。
常见表现:整批插入中断,返回 PDO 异常,错误信息里明确带 Duplicate entry 'xxx' for key 'PRIMARY'。
- 想跳过重复行?必须改用原生 SQL:
Db::execute('INSERT IGNORE INTO ...') - 想存在则更新、不存在则插入?用
replaceInto(),但注意它会先DELETE再INSERT,可能丢失自增 ID 或触发外键级联 - 大批量时建议分片,单次不超过 500 条;否则可能触发 MySQL
max_allowed_packet限制或 PDO 参数绑定超限
addAll 返回 false 或直接报错 “Array to string conversion”
ThinkPHP 3.2 的 addAll 和 TP5/6 的 insertAll 行为不同:addAll 内部会检查 $data[0] 是否为数组,如果传入的批量数据键名是时间戳、UUID 等非数字索引,$data[0] 会是 undefined 或字符串,直接返回 false。
- 修复方式:插入前重置数组下标,
$data = array_values($data),确保是连续数字索引 - TP5/6 中若混用
M('User')->addAll(),注意该方法已废弃,应统一用Db::name('user')->insertAll() - 别依赖
ksort()——它只排键名字母序,不解决非数字索引问题;array_values()才是正解
批量插入后部分字段丢失或写入 NULL
不是 SQL 拼错了,是模型字段缓存(DB_FIELDS_CACHE)没更新,或者 allowField 控制太严。
立即学习“PHP免费学习笔记(深入)”;
- 新增数据库字段后没清缓存?删掉
runtime/Data/_fields/下所有文件,或临时设'DB_FIELDS_CACHE' => false - 用
Db::name()批量插入时,字段名必须和数据库列名完全一致(如user_name不能写成userName);模型方式则需确认$schema包含新字段,或显式调用allowField(true) - Linux 部署时
runtime目录缺x权限,PHP 无法进入子目录生成缓存,表现为“字段读取失败”但无明显报错
事务中 insertAll 失败却没回滚
insertAll 和 updateAll 成功返回影响行数(int),失败抛异常但**不自动终止脚本**。在事务里漏 catch,后续操作照常执行,导致数据不一致。
- 必须显式包裹:
try { Db::startTrans(); ... Db::commit(); } catch (\Exception $e) { Db::rollback(); throw $e; } - 别用
if ($res > 0)判断是否成功——MySQL strict mode 关闭时,部分插入失败可能只返回成功条数,不报错 - TP6 默认开启字段过滤,若批量数据里混入非法字段(比如 URL 路由参数),会被静默丢弃,查日志才能发现
addAll 自动识别。这两处不显眼,但几乎覆盖了 80% 的批量插入失败案例。



















