go服务启动时数据库未就绪需主动等待:用context.withtimeout设30秒总超时,捕获"net.operror""connection refused"等可恢复错误,指数退避重试db.pingcontext;成功后设setconnmaxlifetime(240s)防连接老化。

Go 服务启动时数据库连不上怎么办
服务刚起来就报 driver: bad connection 或 connection refused,不是代码写错了,而是数据库还没 ready。sql.Open 不会阻塞等待,它只初始化连接池;第一次 db.PingContext 很可能失败。
必须在启动阶段主动等,但不能裸写 for 循环无限重试:
- 用
context.WithTimeout包裹整个等待流程,总超时建议设为 30 秒(ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)) - 每次 ping 失败后 sleep 1–2 秒,避免夯住或打爆 DB
- 捕获明确错误:只对
net.OpError、"connection refused"、"timeout"重试;认证失败或 DNS 解析错直接 panic - 成功后调用
db.SetConnMaxLifetime(240 * time.Second),别漏掉
运行中 MySQL 连接突然断了怎么救
*sql.DB 不会自动清理坏连接,断线后首次 db.Query 报 invalid connection 是常态,这不是 bug,是设计使然。
真正要做的不是“修复连接”,而是让业务逻辑能扛住这个错误:
- 只对幂等操作(如
SELECT、GET)做重试;写操作必须带业务 idempotency key 或查状态再决定是否重放 - 重试用指数退避:
100ms → 200ms → 400ms,总耗时 ≤ 2 秒 - 只捕获确定可重试的错误:
driver.ErrBadConn、net.OpError(且.Timeout()为 true)、"use of closed network connection" - 别在每次 Query 前加
db.Ping—— 它不保证下一次 Query 成功,反而增加开销
DSN 里哪些参数真有用,哪些纯属摆设
go-sql-driver/mysql 的 DSN 支持一堆 key,但只有少数几个影响连接行为:
- 有效参数:
timeout=5s(TCP 建连超时)、readTimeout=3s、writeTimeout=3s—— 让错误更快暴露,便于你捕获并重试 - 无效参数:
failover=true、retry=true—— 驱动根本不识别,写了等于没写 - 危险写法:
tcp(127.0.0.1:3306,127.0.0.1:3307)—— 这不是重连,是按顺序尝试地址,任一失败就报错,不自动切 - 必配项:
parseTime=true(避免时间解析错)、loc=Asia/Shanghai(时区一致)
SetConnMaxLifetime 和 SetMaxIdleConns 怎么配才不翻车
这两个参数不设或设错,比不重试还危险 —— 它会让连接池长期复用已失效的连接。
-
db.SetConnMaxLifetime(240 * time.Second):必须比 MySQL 的wait_timeout小(生产通常设 300 秒),留 60 秒缓冲;设 0 = 放弃预防 -
db.SetMaxIdleConns(10):空闲连接上限,太小(如 1)导致频繁建连,太大(如 100)堆积将过期连接 - 必须搭配
db.SetMaxOpenConns(25)使用,否则 idle 连接数失控;生产建议值 ≈ 2–3 × QPS 峰值 - 注意:
SetConnMaxLifetime对所有连接生效,不管它是不是 idle
重连逻辑不在驱动里,也不在 sql.DB 里,而在你调用 db.Query 后的 error 处理分支里。最容易被忽略的是:以为 db.Ping 成功就万事大吉,结果第一个真实查询就崩。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











