sql.Open 不会立即连接数据库,需调用 db.Ping() 确认;MySQL 驱动须用 go module 管理,DSN 必含 tcp(...) 及 charset=utf8mb4、parseTime=true、loc=Local;连接池参数需在 Ping 后设置,且与 DSN 时区配置配套。

sql.Open 不会立刻连上数据库,这是最容易误判的点。必须调用 db.Ping() 才能确认连接可用。
安装 MySQL 驱动必须用 go module 管理
Go 1.16+ 默认启用 module 模式,直接 go get 会失败或装到错误位置。先确保项目根目录有 go.mod:
- 没有
go.mod?运行go mod init your-project-name - 再执行
go get -u github.com/go-sql-driver/mysql(注意不是/go-sql-driver/mysql) - 如果报 proxy 错误,加一行
go env -w GOPROXY=https://goproxy.cn,direct
驱动本身不提供 mysql.Open 这类函数——它只注册自己给 database/sql,所有操作都走标准库接口。
DSN 字符串里这几个参数不能省
常见 DSN:"root:pass@tcp(127.0.0.1:3306)/test?charset=utf8mb4&parseTime=true&loc=Local"
立即学习“go语言免费学习笔记(深入)”;
-
charset=utf8mb4:避免 emoji 或四字节 UTF-8 存储失败 -
parseTime=true:让time.Time能正确解析 DATETIME 字段 -
loc=Local:防止时区错乱(默认是 UTC,查出来的时间可能差 8 小时) - 漏掉
tcp(...)写成root:pass@/test?会报dial unix /tmp/mysql.sock: connect: no such file or directory
连接池配置得在 sql.Open 后立即设
sql.Open 返回的 *sql.DB 是连接池句柄,但默认最大连接数是 0(即无限制),生产环境极易打爆数据库。
- 设最大连接数:
db.SetMaxOpenConns(20) - 设空闲连接数:
db.SetMaxIdleConns(10) - 设连接存活时间:
db.SetConnMaxLifetime(60 * time.Second) - 这些调用必须在
db.Ping()之后、业务逻辑之前做,否则可能被并发请求抢先消耗连接
测试连接时别只看 err == nil
db.Ping() 成功只能说明「此刻能通」,不代表后续查询一定成功。真实问题常出现在:
- 用户没权限(比如只给了 SELECT,却执行 INSERT)→ 报
Error 1142: INSERT command denied - 表不存在 →
Error 1146: Table 'xxx' doesn't exist - 字段类型不匹配(如把 string 当 int 传给
Exec)→driver: couldn't parse []interface {} as int - 建议写个最小验证 SQL:
db.QueryRow("SELECT 1").Scan(&i),比单纯Ping更贴近实际使用路径
真正容易被忽略的是:连接池参数和 DSN 中的 loc、parseTime 必须配套使用。单独开 parseTime 却不设 loc,或者设了 loc=UTC 却没同步改应用时区,都会导致时间字段读写不一致——这种 bug 往往上线后才暴露,且难以复现。



















