Go 1.0起内置database/sql,但建议使用Go ≥ 1.21版本以确保context超时控制稳定及泛型驱动兼容;需显式Ping验证连接、设置连接池参数并正确处理NULL值。

确认 Go 版本是否支持 database/sql 标准库
Go 1.0 起就内置了 database/sql,但低于 1.18 的版本不支持泛型驱动(比如某些新写的 pgx/v5 需要泛型),而低于 1.21 的版本对 context 超时控制的支持也不够稳定。实际写数据库程序时,建议用 go version >= 1.21。
检查方式很简单:
go version
如果输出是 go version go1.20.12 darwin/arm64 这类,就得升级。升级后记得验证 GOPATH 和 GOROOT 没被旧配置污染——常见坑是 which go 和 go env GOROOT 指向不同路径。
选对驱动:PostgreSQL 用 pgx 还是 lib/pq?
lib/pq 是老牌驱动,兼容性好但已归档(不再维护);pgx 性能更好、支持原生类型(如 jsonb 直接映射到 map[string]any),但 v5 要求 Go ≥ 1.18,且默认启用连接池和 context 取消机制。
立即学习“go语言免费学习笔记(深入)”;
- 开发阶段快速验证:用
github.com/jackc/pgx/v5+pgxpool - 若项目必须支持 Go 1.16 或需最小依赖:退回到
github.com/lib/pq(注意它不支持context.WithTimeout自动取消查询) - MySQL 用户别硬套 PostgreSQL 驱动——
github.com/go-sql-driver/mysql才是正解,且连接串里必须加?parseTime=true否则time.Time会解析失败
初始化 DB 连接时绕开 sql.Open 的“假连接”陷阱
sql.Open 只校验 DSN 格式,不真正连数据库;第一次 db.Query 或 db.Ping 才建连。很多新手写完 sql.Open 就以为万事大吉,结果运行时报 driver: bad connection 或卡住。
在 Go 中使用 google/wire 实现编译时依赖注入——wire.NewSet、wire.Build、wire.Bind(接口→实现)、wire.Struct、wire.Value、wire.Interface
正确做法是显式 Ping 并设超时:
db, err := sql.Open("pgx", "postgres://localhost:5432/mydb?sslmode=disable")
if err != nil {
log.Fatal(err)
}
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
if err := db.PingContext(ctx); err != nil {
log.Fatal("can't connect to db:", err)
}另外,db.SetMaxOpenConns(10) 和 db.SetConnMaxLifetime(5 * time.Minute) 必须设——否则高并发下容易耗尽 PostgreSQL 的 max_connections。
用 Scan 读数据时避免类型错位和 NULL 崩溃
PostgreSQL 的 NULL 字段在 Go 里不能直接扫进普通变量,否则 panic:sql: Scan error on column index 1: unsupported Scan, storing driver.Value type <nil> into type *string。
安全写法分两种:
- 字段可能为 NULL:用
sql.NullString/sql.NullInt64等包装类型,再判.Valid - 字段非空且类型明确:确保表结构里写了
NOT NULL,并用对应 Go 类型接收(如int64接BIGINT)
别用 rows.Columns() 动态获取列名再反射赋值——性能差、易出错,不如手写 struct + Scan 明确。
Go 的数据库交互没有魔法,关键在连接生命周期管理、NULL 处理和驱动选型。最常被跳过的其实是 db.Close() ——它不是可有可无的 defer,而是释放底层连接池资源的必要动作,尤其在 CLI 工具或短命服务里。

















