SetConnMaxIdleTime 必须与 SetMaxIdleConns 配合使用才生效,单独设置无效;后者需显式设为正整数且不大于 SetMaxOpenConns;Go 端空闲超时应略小于 MySQL 的 wait_timeout;DSN 中的 timeout 参数不控制空闲超时;GORM 无自动重连,需主动 Ping + 指数退避重试;K8s 环境需强化健康检查。

SetConnMaxIdleTime 必须配合 SetMaxIdleConns 才生效
只调 SetConnMaxIdleTime 却没设 SetMaxIdleConns,等于白配。空闲连接根本进不了池子,自然不会被超时清理。
-
SetMaxIdleConns要显式设为正整数(比如20),否则默认是2,压测时容易耗尽 -
SetMaxIdleConns不能大于SetMaxOpenConns,建议按SetMaxOpenConns * 0.2设 - MySQL 的
wait_timeout是服务端断连依据,Go 端SetConnMaxIdleTime应设为略小值(如 DB 设60s,Go 设45 * time.Second)
DSN 中的 timeout 不是空闲超时,别混淆
很多人在 DSN 里写 timeout=10s 或 readTimeout=30s,以为能控制连接空闲时间——完全误解。这些参数只影响建连或单次读写,和连接池生命周期无关。
-
timeout:仅控制sql.Open阶段 TCP 握手+认证耗时,连不上就失败,不涉及已建好的连接 -
readTimeout/writeTimeout:作用于单次Query或Exec的 I/O,超时后连接仍留在池中 - 真正管“连接空闲多久该关”的,只有
SetConnMaxIdleTime,且必须通过db.DB()获取底层*sql.DB后调用
连接断开后 GORM 不会自动重连,得靠 Ping + 重试兜底
GORM 本身没有内置断线自动重连逻辑。连接被 MySQL 主动 kill(比如 wait_timeout 触发)后,下次复用会报 invalid connection,此时需主动探测并恢复。
- 高频写场景下,建议在关键操作前加
db.Ping(),失败则触发重试逻辑 - 重试推荐用指数退避,例如首次延迟
100ms,每次翻倍,最多3次 - 注意错误类型过滤:只对
driver.ErrBadConn、io.EOF、net.OpError这类临时错误重试,认证失败等永久错误直接返回
Kubernetes 环境下连接失效更频繁,需强化健康检查
Pod 重建、Service IP 变更、网络策略波动都会导致连接中断。光靠 SetConnMaxIdleTime 不够,得叠加主动探测。
- 在 readiness probe 中加入
db.Ping(),避免流量打到已失连的实例 - 结合
SetConnMaxLifetime(设为略小于 MySQLmax_connections的活跃周期),强制轮换长连接,减少 stale connection 积累 - 环境变量注入数据库地址时,避免硬编码 IP,优先用 Service 名称 + DNS 解析,降低因 Pod IP 变更引发的连接失败
实际生效的关键点很窄:SetConnMaxIdleTime 和 SetMaxIdleConns 必须同时设置,且值要匹配 MySQL 的超时策略;所有“自动恢复”都依赖你主动调用 Ping 并实现重试,GORM 不会替你做这件事。


















