sql.db 本身就是内置连接池,无需sql框架管理;必须手动调用 db.ping() 验证连通性,合理设置 setmaxopenconns(建议数据库上限的60%~80%)、setmaxidleconns 和 setconnmaxlifetime。

别用 SQL 框架管连接池,database/sql 本身就有,且必须手动调
很多人搜“SQL 框架优化连接池”,默认以为 GORM、sqlx 或 Ent 这类库能帮你自动配好池子——其实它们只是 database/sql 的封装层,底层仍依赖你手调 *sql.DB 的三个关键方法。框架不替你设 SetMaxOpenConns,也不帮你做 db.Ping(),更不会根据 RDS 的 wait_timeout 自动算 SetConnMaxLifetime。靠框架默认值上线,等于把连接池交给运气。
sql.Open() 后不调 db.Ping() 就发请求?首条 Query 必崩
现象:服务日志显示 “DB initialized”,但第一个 HTTP 请求就卡住或报 dial tcp: i/o timeout 或 access denied。
-
sql.Open()只注册驱动、解析 DSN,不建真实连接 - 真正拨号发生在第一次
db.Query()、db.Exec()或db.Ping() - 没显式
db.Ping(),错误就延迟暴露,排查时得翻链路日志、查 DNS、重试连通性,成本陡增 - 正确做法:紧随
sql.Open()后立即if err := db.Ping(); err != nil { /* 记录并退出 */ }
SetMaxOpenConns 设太高或太低,都会让 WaitCount 疯涨
现象:QPS 没变,但接口 P95 延迟突然跳高,db.Stats().WaitCount 持续上升,WaitDuration 累积增长。
- 设太低(如
SetMaxOpenConns(5)):并发稍高就排队,goroutine 卡在acquireConn上 - 设太高(如
SetMaxOpenConns(0)或500):打爆 MySQL 的max_connections(默认 151),触发ERROR 1040: Too many connections;PostgreSQL 则可能耗尽 backend 进程 - 合理值 = 数据库
max_connections× 0.6~0.8,再留余量给备份/监控;MySQL 生产常见 100~120,PG 按每核 ≈20 估算 - 验证方式:
db.Stats().OpenConnections长期 > 90%MaxOpenConns→ 加;长期
事务里混用 db.Query 和 tx.Query?连接永远不归还
现象:db.Stats().InUse 持续高位,WaitCount 不涨,数据库连接数缓慢爬升,直到 Too many connections。
- 事务内调
db.Query()会从全局池另取连接,既不参与当前事务,又占着连接不放 -
tx.Query()和tx.Exec()才复用事务绑定的连接;所有 SQL 必须走tx实例 -
sql.Tx必须显式Commit()或Rollback(),漏写等于泄漏 - 开启事务必须带 context:
db.BeginTx(ctx, &sql.TxOptions{}),其中ctx建议设 5s 超时
最常被忽略的不是参数怎么设,而是 rows.Close() 漏写、tx 忘提交、db.Ping() 没做——这些比 SetConnMaxLifetime 的毫秒级误差更容易让服务在凌晨三点挂掉。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











