Exec 返回 sql.ErrNoRows 不是误报,但该错误仅由 QueryRow/Scan 在结果为空时触发,与 Exec 无关;批量插入失败应检查具体驱动错误如 pq.Error 或 mysql.MySQLError。

Go 批量插入时 Exec 返回 sql.ErrNoRows 是误报吗?
不是误报,但大概率是你没理解它的触发场景——sql.ErrNoRows 只会在使用 QueryRow 或 Scan 类方法且结果集为空时返回,和 Exec 无关。批量插入用 Exec 出错,实际返回的是具体数据库驱动的错误,比如 PostgreSQL 的 pq.Error 或 MySQL 的 mysql.MySQLError。直接判空或只检查 ErrNoRows 会漏掉真实失败。
实操建议:
立即学习“go语言免费学习笔记(深入)”;
- 永远用
if err != nil检查Exec结果,不要跳过或仅做strings.Contains(err.Error(), "duplicate")这类脆弱判断 - 对 PostgreSQL,类型断言
err.(*pq.Error)后看Code字段(如"23505"表示唯一约束冲突) - MySQL 驱动下,断言
err.(*mysql.MySQLError),检查Number(如1062是重复键) - 别依赖错误字符串匹配——字段名、提示语随驱动版本或 locale 变化,不可靠
用 INSERT ... ON CONFLICT DO NOTHING 还是先 SELECT 再 INSERT?
后者在高并发下必然产生竞态,前者才是 PostgreSQL 批量防重的正解。但注意:它只处理“冲突即忽略”,不返回哪些行被跳过,也无法捕获冲突细节。
实操建议:
立即学习“go语言免费学习笔记(深入)”;
- 单条插入用
ON CONFLICT DO NOTHING RETURNING id,能通过Query获取成功插入的主键;但批量时不支持RETURNING与多值VALUES直接配合(除非用UNNEST) - 真要批量并知道哪些失败,改用
INSERT INTO ... SELECT ... WHERE NOT EXISTS (...)+ 临时表或 CTE,但性能下降明显 - 更实用的折中:插入前用
SELECT id FROM table WHERE id = ANY($1)预检 ID 集合,再用INSERT ... ON CONFLICT,两次查询换确定性 - MySQL 没有原生
ON CONFLICT,得用INSERT IGNORE或REPLACE INTO,但后者会触发删除+插入,影响自增 ID 和外键级联
pgx.Batch 和原生 sql.DB 批处理性能差多少?
在 PostgreSQL 场景下,pgx.Batch 通常快 3–5 倍,因为它复用连接、避免多次 round-trip、支持二进制协议传输。但代价是错误粒度变粗——整个 batch 失败时,你不知道哪条语句出问题。
动态WEB网站中的PHP和MySQL详细反映实际程序的需求,仔细地探讨外部数据的验证(例如信用卡卡号的格式)、用户登录以及如何使用模板建立网页的标准外观。动态WEB网站中的PHP和MySQL的内容不仅仅是这些。书中还提到如何串联JavaScript与PHP让用户操作时更快、更方便。还有正确处理用户输入错误的方法,让网站看起来更专业。另外还引入大量来自PEAR外挂函数库的强大功能,对常用的、强大的包
实操建议:
立即学习“go语言免费学习笔记(深入)”;
- 用
pgx.Batch时,必须遍历batchResults调用Exec并检查每个error,不能只看 batch 整体是否成功 - 如果某条语句失败,
pgx不会自动 rollback 前面成功的语句,需自行控制事务边界(把 batch 放在Begin()内) -
sql.DB的Prepare+ 循环Exec更易调试,适合中小批量( - 别盲目开 10000 条一包——PostgreSQL 默认
max_prepared_statements=100,超限会报"prepared statement does not exist"
怎么让失败的记录不阻塞后续插入?
核心是放弃“全批原子性”,接受部分成功。但不能简单 try-catch 吞掉错误,否则丢失上下文和监控能力。
实操建议:
立即学习“go语言免费学习笔记(深入)”;
- 按业务意义分组,比如按时间分区或用户 ID 哈希,每组 100–500 行,组内失败则整组重试或落库待人工处理
- 用结构体封装每条数据 + 状态字段(
status string // "pending", "success", "failed"),失败时更新状态并记录err.Error(),而非丢弃 - 避免在循环里直接
log.Printf—— 高频插入时 I/O 成瓶颈,改用缓冲日志或异步上报 - 如果失败率持续 > 5%,优先查数据质量(空字段、超长字符串、非法时间戳),而不是堆重试逻辑
真正难的不是语法或 API,是决定哪些错误可忽略、哪些必须告警、哪些要人工介入——这得贴着你的业务约束来划线,代码只是执行者。









