必须为每个mysql实例创建独立的*sql.db,通过函数参数传入并显式调用db.ping()验证连通性;并发查询需用errgroup.group或sync.waitgroup同步,避免goroutine闭包捕获错误和结果错乱。

怎么用一个函数同时查多个 MySQL 实例?
不能直接复用单个 *sql.DB 连接对象去“切换”数据库实例——每个 *sql.DB 对应唯一一个 DSN,硬改连接字符串会引发竞态或 panic。正确做法是为每个实例维护独立的 *sql.DB,再把它们传给查询函数。
- 先用不同 DSN 分别调用
sql.Open(),得到多个*sql.DB实例(记得调db.Ping()验证连通性) - 查询函数签名要接受
*sql.DB作为第一个参数,比如:func queryUser(db *sql.DB, id int) (User, error) - 避免在函数内部做连接池管理(如反复
sql.Open),否则会泄漏 goroutine 和连接
并发查多个库时,为什么结果顺序总不对?
Go 默认不保证 goroutine 执行顺序,如果用 go queryUser(db1, 123) + go queryUser(db2, 123) 并发跑,返回值写入 slice 的位置可能错乱。必须显式同步。
- 用
sync.WaitGroup等所有 goroutine 完成,配合带索引的 channel 或预分配 slice + mutex 写入 - 更稳妥的是用
errgroup.Group(来自golang.org/x/sync/errgroup),它天然支持并发控制和错误传播 - 别依赖 goroutine 启动顺序,比如
for i := range dbs { go f(dbs[i]) }中的i会被闭包捕获成最后值,必须写成go f(dbs[i])→go func(db *sql.DB) { f(db) }(dbs[i])
PostgreSQL 和 SQLite 能套用同一套查询逻辑吗?
可以,但要注意 SQL 方言差异和驱动行为区别。Go 的 database/sql 接口是抽象的,只要底层驱动实现了标准接口,上层代码就能复用。
使用 uber-go/dig 在 Golang 中实现依赖注入——基于反射容器,提供 Provide/Invoke、dig.In/dig.Out 参数与结果对象,支持命名依赖等
- 参数占位符不同:MySQL 用
?,PostgreSQL 用$1,SQLite 也用?—— 写查询时得按目标驱动语法来,不能混用 - 自动提交行为:SQLite 默认开启 auto-commit,而 PostgreSQL/MySQL 需显式
db.Exec("BEGIN")控制事务,跨库函数若涉及事务就得拆开处理 - 类型映射差异:比如 PostgreSQL 的
JSONB字段在 Scan 时需用json.RawMessage,而 MySQL 的JSON可直转 struct,统一处理容易 panic
连接太多导致 “too many open files” 怎么办?
每个 *sql.DB 默认最大打开连接数是 0(无限制),多个实例叠加后极易突破系统 ulimit。这不是代码 bug,是资源配额没控住。
- 对每个
*sql.DB显式调db.SetMaxOpenConns(n),建议设为 5–10(视实例负载定),别留 0 - 调
db.SetMaxIdleConns(n)控制空闲连接数,避免长期占着 fd 不放(尤其短连接场景) - Linux 下用
ulimit -n查当前限制,生产环境至少设到 4096;Docker 容器需在docker run --ulimit nofile=4096:4096中显式指定
多实例不是“堆连接就行”,关键在连接池粒度和系统边界对齐。漏设 SetMaxOpenConns 是线上最常被忽略的点。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










