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

sql.Open 不是“连上数据库”,只是初始化连接池
很多人看到 sql.Open 返回 err == nil 就以为连上了,结果后续 db.Query 或 db.Ping() 突然 panic。这是因为 sql.Open 只做三件事:校验 DSN 格式、注册驱动、配置连接池参数——它根本不会发任何网络包。
- 真实建连发生在第一次调用
db.Ping()、db.Query()或db.Exec()时 - 必须在
sql.Open后立刻加if err := db.Ping(); err != nil,否则上线后第一个请求就可能失败 - 本地能通但线上报
dial tcp: i/o timeout?大概率是容器没暴露端口、DNS 解析失败,或防火墙拦了 3306/5432
DSN 必须带数据库名,不能靠 USE 语句切换
写 db.Exec("USE mydb") 是错的。MySQL 连接池里的每个连接是独立上下文,USE 只影响当前连接,下次从池里取的连接又回到未选库状态,紧接着查表就会报 Error 1046: No database selected。
- DSN 格式必须包含库名:
user:pass@tcp(127.0.0.1:3306)/myapp?parseTime=true&loc=Asia%2FShanghai - PostgreSQL 的 DSN 类似:
host=localhost port=5432 user=demo_user password=demo_pass dbname=go_pg_demo sslmode=disable - 密码含特殊字符(如
@、/)必须用url.QueryEscape编码,否则 DSN 解析失败
连接池不调参 = 生产事故
默认 MaxOpenConns=0(无上限)、MaxIdleConns=2、ConnMaxLifetime=0,高并发下 MySQL 很快报 Too many connections,或复用被 server kill 的 stale connection 导致 invalid connection。
Go语言(Golang)1.26.0版本提供 Go 官方 Windows amd64 MSI 安装包下载入口,版本号 1.26.0,可用于旧项目维护、兼容性测试和指定版本开发环境配置。
- 上线前必设:
db.SetMaxOpenConns(20)、db.SetMaxIdleConns(10)、db.SetConnMaxLifetime(60 * time.Second) -
MaxOpenConns建议 ≤ MySQL 的max_connections(云数据库常为 100~200),留余量给其他服务 - 别在 handler 里反复
sql.Open+db.Close,全局复用一个*sql.DB实例
Query 后忘记 rows.Close() 会吃光连接
db.Query 返回 *sql.Rows,它背后占着连接池里的一个连接。即使你 for 循环读完所有数据,连接也不会自动归还——除非显式调用 rows.Close()。
- 典型泄漏写法:
rows, _ := db.Query("SELECT id FROM users"); for rows.Next() { /* ... */ }—— 缺rows.Close() - 正确写法:
rows, err := db.Query(...); if err != nil { ... }; defer rows.Close() - 更安全的是用
db.QueryRow处理单行结果,它内部自动 Close,无需手动管理
连接池生命周期、DSN 参数、资源释放这三点,漏掉任何一个都可能让服务在压测或上线后突然卡死。不是代码跑起来就算完事,得盯着连接数、错误日志和慢查询才真正算稳住。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










