sql.open仅初始化连接池且不建立真实连接,必须立即调用db.ping()验证连通性;dsn需含parsetime=true和数据库名,连接池参数须显式配置,query后必须rows.close()防泄漏。

sql.Open 返回的是连接池句柄,不是单次连接 —— 它不校验数据库是否可达,也不触发网络握手。跳过 DB.Ping() 会导致首次查询才暴露连接失败,错误堆栈深、定位困难。
DSN 字符串必须严格符合格式,且含必要参数
MySQL 驱动要求 DSN 格式为:user:password@tcp(host:port)/dbname?param1=value1¶m2=value2。漏掉任意关键参数,轻则时间字段扫描失败,重则连接静默失败。
-
parseTime=true必须显式加上,否则time.Time类型字段会报sql: Scan error on column index 0 -
loc=Local或loc=Asia/Shanghai要明确指定,否则 MySQL 返回的时间可能被解析成 UTC 或零值 - 密码含
@、/、:等特殊字符时,必须用url.PathEscape编码,否则 DSN 解析错位 - 数据库名不能为空 —— 即使只打算连上不选库,也得填一个合法库名,
sql.Open不支持无库连接
必须显式调用 DB.Ping() 做启动时连通性验证
Iris 启动阶段是发现连接问题的黄金窗口。把 DB.Ping() 放在初始化后立刻执行,能确保服务启动失败早于路由注册,避免请求进来才 panic。
- 错误示例:
db, _ := sql.Open("mysql", dsn)后直接app.RegisterValue("db", db)—— 这里没做任何可用性检查 - 正确做法:接
if err := db.Ping(); err != nil { log.Fatal("mysql unreachable:", err) } - 注意:
Ping()会阻塞直到完成 TCP 握手 + MySQL 认证,超时由底层 net.Conn 控制(默认 30s),如需缩短可提前设置db.SetConnMaxLifetime和上下文超时
SetMaxIdleConns 和 SetMaxOpenConns 不是越大越好
Iris 的 HTTP handler 是短生命周期的,每个 db.Query 或 db.Exec 都从池中取连接。设太高反而导致 MySQL 侧连接数爆满、TIME_WAIT 积压或权限拒绝(Too many connections)。
- 典型 Web 场景建议值:
SetMaxIdleConns(10)、SetMaxOpenConns(50),具体按预估 QPS × 平均查询耗时 × 安全系数(比如 2~3)估算 -
SetConnMaxLifetime(time.Hour)推荐设置,避免长连接因中间网络设备断连后变成僵尸连接 - 别漏掉
db.SetMaxIdleTime(30 * time.Second)(Go 1.15+),它控制空闲连接最大存活时间,比旧版SetConnMaxLifetime更精准
最容易被忽略的是 DSN 中 parseTime 和 loc 的缺失 —— 它们不会让连接失败,但会让时间字段读出来是零值或 panic,而且问题只在特定数据出现时才暴露,调试成本远高于启动时加两个参数。











