sql.DB本身就是连接池,必须手动配置SetMaxOpenConns(建议数据库max_connections的60%~80%)、SetMaxIdleConns(≤前者且合理比例)和SetConnMaxLifetime(略小于DB wait_timeout),并紧随sql.Open()调用db.Ping()验证连通性,事务中必须全程使用tx.Query()且显式Commit/Rollback。

别自己写连接池,也别指望 GORM 或 sqlx 帮你配好——sql.DB 本身已是连接池,但默认配置在生产环境必然出事。
sql.Open() 后不调 db.Ping() 就上线?首请求必崩
现象:服务日志显示 “DB initialized”,但第一个 HTTP 请求卡住或报 dial tcp: i/o timeout、access denied。
原因:sql.Open() 只解析 DSN、初始化结构体,不建真实连接;真正拨号发生在第一次 db.Query()、db.Exec() 或 db.Ping()。
错误延迟暴露,排查时得翻链路日志、重试连通性,成本陡增。
必须做:
• 紧随 sql.Open() 后立即执行 if err := db.Ping(); err != nil { /* 记录并退出 */ }
• 别把 db.Ping() 当健康检查 endpoint 放在 k8s readiness probe 里——它只测单次连通性,不反映空闲连接状态
SetMaxOpenConns 和 SetMaxIdleConns 怎么设才不踩坑
现象:QPS 没变,P95 延迟跳高,db.Stats().WaitCount 持续上升;或数据库报 ERROR 1040: Too many connections。SetMaxOpenConns 控制“同时最多有多少个活跃连接(含忙 + 空闲)”,SetMaxIdleConns 只管“空闲连接池里最多留几个”。
常见误配:
• SetMaxIdleConns 设得比 SetMaxOpenConns 大 → Go 1.12+ 直接 panic,报错 max idle conns exceeds max open conns
• SetMaxOpenConns(0)(无限制)→ 打爆 MySQL 默认 max_connections=151 或 PG 的 backend 进程上限
合理值:
• SetMaxOpenConns = 数据库 max_connections × 0.6~0.8,MySQL 生产常见 100~120,PG 按每核 ≈20 估算
• SetMaxIdleConns = SetMaxOpenConns × 0.5 左右,且 ≥5;必须 ≤ 前者
事务里混用 db.Query() 和 tx.Query()?连接永远不归还
现象:db.Stats().InUse 持续高位,WaitCount 不涨,数据库连接数缓慢爬升,直到 Too many connections。
原因:事务内调 db.Query() 会从全局池另取连接,既不参与当前事务,又占着连接不放;只有 tx.Query() 和 tx.Exec() 复用事务绑定的连接。
必须遵守:
• 事务内所有 SQL 必须走 *sql.Tx 实例,绝不能穿插 db.*() 调用
• sql.Tx 必须显式 Commit() 或 Rollback(),漏写等于泄漏
• 开启事务必须带 context:db.BeginTx(ctx, &sql.TxOptions{}),其中 ctx 建议设 5s 超时
使用 uber-go/dig 在 Golang 中实现依赖注入——基于反射容器,提供 Provide/Invoke、dig.In/dig.Out 参数与结果对象,支持命名依赖等
立即学习“go语言免费学习笔记(深入)”;
SetConnMaxLifetime 不是保活,是主动换新
现象:偶发 invalid connection,尤其在 RDS 或 ProxySQL 环境下。
原因:SetConnMaxLifetime 不发心跳,也不检测连接是否可用,只是强制连接从创建起最多活多久,到期就关掉,下次需要时新建。
典型场景:
• RDS 默认 wait_timeout=30m → 设 SetConnMaxLifetime(25 * time.Minute) 避免取到被 DB 主动断开的连接
• 云厂商中间件对长连接复用不稳定 → 缩短 lifetime(如 10~30 秒)可降低偶发通信错误率
注意:
• 设为 0 表示永不过期(不推荐)
• 设太短(如 1s)会导致频繁 handshake,增加延迟和 TIME_WAIT
最常被忽略的不是参数怎么设,而是 rows.Close() 漏写、tx 忘提交、db.Ping() 没做——这些比毫秒级的 SetConnMaxLifetime 误差更容易让服务在凌晨挂掉。

















