跳转到主内容
极星编程网:以代码为星,赴技术山海!

Golang怎么MySQL批量插入_Golang如何一次性插入多条数据提高性能【技巧】

MySQL批量插入应使用INSERT INTO ... VALUES (...), (...)单语句多值形式,避免循环单条执行;需控制单次行数(建议≤1000)、显式事务(≤5000行)、防SQL注入(用?占位)、合理处理主键冲突(优先ON DUPLICATE KEY UPDATE)。 MySQL批量插入用
INSERT INTO ... VALUES (...), (...)
,别用循环单条 Go里最常见性能陷阱就是对每条数据调用一次
db.Exec
——网络往返+事务开销直接拖垮吞吐。正确做法是拼成一条多值
INSERT
语句,让MySQL一次解析、一次写入。 注意不是所有场景都适合无限拼接:MySQL默认
max_allowed_packet
约4MB,超长SQL会报错
MySQL server has gone away
。实际建议单次不超过1000行(视单行数据大小动态调整)。 用
strings.Builder
拼SQL,避免
+=
字符串反复分配 参数必须用
?
占位符,不要字符串插值,防SQL注入 值列表末尾不加逗号,拼接逻辑要处理好边界 用
sqlx.In
或
database/sql
原生方式处理参数绑定 手动拼
VALUES (?, ?), (?, ?)
容易出错,尤其参数数量和顺序对不上时。推荐两种稳妥方案: 如果项目已用
sqlx
:先调
sqlx.In
生成带
?
的SQL和展开后的参数切片,再用
db.MustExec
执行 纯
database/sql
:自己写个辅助函数,把
[]interface{}
按每批N个分组,每组生成对应数量的
?
,再
append
所有参数到一个大切片 别直接把结构体切片传给
Exec
——
database/sql
不支持自动解构,会报
unsupported type []MyStruct
。 立即学习 “ go语言免费学习笔记(深入) ”; 事务控制必须显式开启,否则批量没意义 即使用了批量SQL,如果每条还走自动提交,性能提升有限。MySQL在事务内批量写入才能真正减少日志刷盘和索引更新次数。 用
tx, err := db.Begin()
开始,成功后
tx.Commit()
,失败
tx.Rollback()
别依赖
defer tx.Rollback()
——它会在函数返回时执行,可能掩盖真实错误 大事务有风险:锁持有时间变长,可能阻塞其他查询;崩溃恢复也更慢。建议单次事务控制在5000行以内 错误现象:
ERROR 1205 (HY000): Deadlock found when trying to get lock
,往往就是事务太大、锁范围太广导致的。 注意
ON DUPLICATE KEY UPDATE
和
REPLACE INTO
的语义差异 需要去重插入时,很多人直接上
REPLACE INTO
,但它本质是
DELETE + INSERT
,会引发自增ID跳变、触发器重复执行、外键约束检查两次等问题。 优先用
INSERT ... ON DUPLICATE KEY UPDATE
,只更新指定字段,行为可控 多个唯一键冲突时,
ON DUPLICATE KEY UPDATE
只触发一次,而
REPLACE
可能删多条 如果表有
ON UPDATE CURRENT_TIMESTAMP
字段,
ON DUPLICATE KEY UPDATE
会触发它,
REPLACE
也会——这点常被忽略 批量场景下,
VALUES(col1)
在
UPDATE
子句里可引用刚插入的值,比如
UPDATE count = count + VALUES(count)
,这个语法只有批量插入才支持。 批量插入真正的复杂点不在拼SQL,而在**分批大小、事务粒度、错误定位、主键冲突策略**四者的平衡。线上跑之前,务必用真实数据量压测,观察MySQL的
Threads_running
和
Innodb_row_lock_time_avg
指标。

相关文章