go的*sql.db本身就是连接池,需配置setmaxopenconns(≤数据库max_connections×0.8)、setmaxidleconns(为其1/2~2/3)和setconnmaxlifetime(30s~5分钟),并调用db.ping()验证,全局复用且避免误调close。

Go 的 *sql.DB 本身是连接池,不是“需要你手动维护”的对象——只要配置对、复用对、不乱 Close,它自己就能长期健康运转。盲目写定时清理、重连逻辑反而引入 bug。
SetMaxOpenConns 设太高反而拖慢请求
默认值 0(无上限)在生产环境极其危险,PostgreSQL 或 MySQL 很快报 too many connections;但设成 200 并不等于吞吐翻倍,实际可能更慢。
- 高
MaxOpenConns会导致大量空闲连接长期占用 DB 线程和内存,尤其在云数据库(如 AWS RDS、阿里云 PolarDB)上,会提前触达实例连接数上限 - TLS 握手、认证开销随连接数线性增长,实测从 20 → 100 连接,单次建连耗时可能翻倍
- 推荐值:MySQL 控制在
100~200,PostgreSQL 按 CPU 核数 × 20 估算;再乘以 1.2~1.5 倍作为峰值缓冲 - 必须显式调用
db.SetMaxOpenConns(n),别依赖默认
SetMaxIdleConns 和 SetConnMaxIdleTime 必须配对设
只设 SetMaxIdleConns 不设 SetConnMaxIdleTime(Go 1.15+),空闲连接会一直挂着,变成“僵尸连接”;反之只设 idle time,健康连接可能被误杀,引发重连抖动。
使用 uber-go/dig 在 Golang 中实现依赖注入——基于反射容器,提供 Provide/Invoke、dig.In/dig.Out 参数与结果对象,支持命名依赖等
-
SetMaxIdleConns一般设为MaxOpenConns的 1/2 到 2/3(例如最大 50,空闲设 25~30) -
SetConnMaxIdleTime必须小于SetConnMaxLifetime,常见设15m~20m - 云环境(K8s Pod 重启、DB 故障切换)下,两者都为
0(禁用)极易导致连接泄漏或复用失败
事务内混用 db 和 tx 会饿死连接池
事务 *sql.Tx 绑定专属连接,直到 Commit() 或 Rollback() 才释放;若在事务里穿插调用 db.Query,那个连接不会归还池子,其他 goroutine 就得干等。
- 事务内所有 SQL 操作必须统一走
tx.Query/tx.Exec,禁止混用db方法 - 避免在事务中做 HTTP 请求、文件读写等耗时操作,防止连接被 hold 超过 5 秒
- 用
context.WithTimeout(ctx, 5*time.Second)包裹db.BeginTx,防止单个事务卡死整个池
不查 db.Stats() 就等于盲调参数
db.Stats() 返回的指标才是真实水位线,日志和压测数据都只是间接参考。
-
WaitCount和WaitDuration持续上涨?说明MaxOpenConns不够,或者查询太慢堵住了连接 -
MaxIdleClosed高?说明MaxIdleConns设太高,或业务低峰期连接利用率极低 -
OpenConnections长期接近MaxOpenConns?要检查是否有rows没defer rows.Close(),或事务没提交/回滚 - 建议每 30 秒采集一次
db.Stats(),接入 Prometheus,对WaitDuration > 100ms做告警
最常被忽略的点:*sql.DB 是全局复用的单例,不是每次 HTTP 请求 new 一个;db.Close() 只应在进程退出前调用一次,日常运行中绝不该出现 —— 它关的是整个池,不是某条连接。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










