能连上不代表配置正确,必须用db.pingcontext()验证真实连接;需设setmaxopenconns、setmaxidleconns和setconnmaxlifetime防线上事故;驱动须下划线导入,dsn应通过环境变量安全注入。

能连上,不代表配置对了;能跑通,不等于线上不出事。 Go 连本地数据库最常卡在驱动没注册、连接池没调、DSN 写错这三步,而不是代码逻辑本身。
sql.Open 之后必须 db.Ping() 才算真正连上
很多人以为 sql.Open 返回 err 就代表连不上,其实它只校验 DSN 格式,不建真实连接。哪怕你写成 "mysql://localhost:9999",sql.Open 也成功返回 *sql.DB。
- PostgreSQL DSN 示例:
"host=localhost port=5432 user=dev password=123 dbname=test sslmode=disable" - MySQL DSN 示例:
"dev:123@tcp(127.0.0.1:3306)/test?parseTime=true&loc=Local"(注意&是 HTML 实体,代码里写&) - 调用
db.Ping()或更安全的db.PingContext(ctx)才会触发 TCP 握手和认证 - 如果报
"dial tcp 127.0.0.1:3306: connect: connection refused",先确认 MySQL/PostgreSQL 进程是否真在运行、端口是否监听(netstat -tuln | grep :3306)
连接池参数不设就是线上事故的温床
Go 的 *sql.DB 默认连接池是“无上限+永不过期”,本地开发可能跑得动,一上生产立刻被 max_connections 拦住或堆积大量 TIME_WAIT。
使用 uber-go/dig 在 Golang 中实现依赖注入——基于反射容器,提供 Provide/Invoke、dig.In/dig.Out 参数与结果对象,支持命名依赖等
-
db.SetMaxOpenConns(20):别设成 100,本地开发建议 10–25,值过大反而让数据库拒绝新连接 -
db.SetMaxIdleConns(10):空闲连接数不宜超过MaxOpenConns,否则冷启动后大量连接闲置 -
db.SetConnMaxLifetime(5 * time.Minute):防止数据库重启后连接池里还存着 stale 连接,5 分钟比 30 分钟更适合本地调试 - 漏设
SetConnMaxLifetime会导致查询偶尔报"server closed the connection",尤其在 Docker 环境下容器重启后
驱动导入必须用下划线匿名导入
Go 标准库 database/sql 是接口层,不带任何驱动实现。sql.Open("mysql", ...) 会 panic:"sql: unknown driver \"mysql\"",除非驱动包被显式加载。
- PostgreSQL(lib/pq):
import _ "github.com/lib/pq" - PostgreSQL(pgx/v5):
import _ "github.com/jackc/pgx/v5"(注意 v5 后需额外 importpgxpool才支持连接池) - MySQL:
import _ "github.com/go-sql-driver/mysql" - SQLite3:
import _ "github.com/mattn/go-sqlite3"(Windows 用户需确保有 MinGW 或 TDM-GCC) - go mod tidy 后检查
go.sum是否包含对应驱动哈希,避免 CI 环境因缓存导致驱动缺失
敏感信息别硬编码,用环境变量注入 DSN
本地开发时把密码写死在代码里,既不安全也不便切换环境。用 os.Getenv 拆解 DSN 更可控。
- 定义环境变量:
export DB_USER=dev && export DB_PASS=123 && export DB_HOST=localhost - 拼接 DSN:
dsn := fmt.Sprintf("%s:%s@tcp(%s:3306)/test?parseTime=true&loc=Local", os.Getenv("DB_USER"), os.Getenv("DB_PASS"), os.Getenv("DB_HOST")) - 用
godotenv.Load()加载 .env 文件更省事,但上线时仍应优先走系统环境变量 - 如果 DSN 中含特殊字符(如密码含
@或/),必须 URL encode,否则sql.Open解析失败
最容易被忽略的是:事务内混用 db.Query 和 tx.Query —— 前者走连接池,后者走事务上下文,一个 rollback 了,另一个早执行完了,数据一致性完全失控。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










