必须传入postgres.open(dsn)和*gorm.config{},其中dsn为key=value或url格式字符串(如"host=localhost user=postgres password=123456 dbname=test port=5432 sslmode=disable"),且需提前go get gorm.io/driver/postgres。

gorm.Open 传什么参数才能连上 PostgreSQL
必须显式传入 postgres.Open(dsn),而不是字符串或自定义 driver name。GORM v2+ 已移除内置驱动,gorm.Open 第一个参数必须是实现了 gorm.Dialector 接口的实例,postgres.Open 就是官方提供的标准实现。
DSN 必须是 key=value 形式(如 "host=localhost user=postgres password=123456 dbname=test port=5432 sslmode=disable")或 URL 形式(如 "postgres://postgres:123456@localhost:5432/test?sslmode=disable")。二者等价,但 URL 形式对特殊字符(如密码含 @ 或 /)更安全。
-
sslmode=disable在本地开发几乎必加;PostgreSQL 默认启用 SSL,不加会导致连接卡住或报dial tcp: lookup ...: no such host类似错误 -
port=5432显式写上,避免误连到 MySQL 的 3306 或其他服务 -
TimeZone=Asia/Shanghai建议加上,否则 time.Time 字段可能被存成 UTC 或解析错时区
pgx vs lib/pq:该用哪个驱动
推荐直接用 gorm.io/driver/postgres —— 它底层默认封装的是 pgx(v5+),不是 lib/pq。你不需要手动 import pgx 或 lib/pq,只要 go get gorm.io/driver/postgres 即可。
旧项目若还在用 lib/pq,需注意:_ "github.com/lib/pq" 这种匿名导入对 GORM 无效;GORM 不走 database/sql 的驱动注册机制,所以即使 import 了 lib/pq,gorm.Open("postgres", dsn) 仍会失败(v2+ 已不支持字符串 driver name)。
使用 uber-go/dig 在 Golang 中实现依赖注入——基于反射容器,提供 Provide/Invoke、dig.In/dig.Out 参数与结果对象,支持命名依赖等
-
pgx性能更好,原生支持context.Context,连接池可控,还支持pgxpool直接接管 -
lib/pq已归档(archived),不再维护,仅建议用于极老项目兼容 - 如果要用
pgxpool.Pool实例初始化 GORM(比如想精细控制最大连接数),得自己构造postgres.Dialector并传.Driver字段,不是直接调postgres.Open
为什么 db := gorm.Open(...) 后立刻调 .First() 才报错
gorm.Open 只做配置解析和对象初始化,**不建立物理连接**。它返回的 *gorm.DB 是个“待命状态”,直到第一次执行查询、插入等操作时才真正拨号。
这意味着:DSN 写错、PostgreSQL 没启动、防火墙拦住端口……这些全都不会在 gorm.Open 阶段暴露。最容易踩的坑是上线前没做探活,结果第一个 HTTP 请求就 panic。
- 最简验证:运行
db.Exec("SELECT 1").Error,非 nil 表示连不上 - 更严谨点:用
db.Raw("SELECT 1").Scan(&struct{}{}),避免忽略 scan 错误 - 如果用了
pgx底层,还能拿到连接池:db.Config.ConnPool.(*pgxpool.Pool).Ping(ctx) -
db.Error是上一次操作的错误,不能用来判断当前连接是否健康 —— 它不是实时状态快照
连接池与超时配置容易被忽略的点
GORM 自身不管理连接池,它把这事完全交给底层驱动(pgx 或 lib/pq)。所以连接池参数必须通过 DSN 或驱动级配置传进去,GORM 的 Config 里没有 MaxOpenConns 这类字段。
例如用 pgx 时,可在 DSN 后加 &max_conns=20&min_conns=5,或更推荐的方式:先创建 pgxpool.Config,再用它构造 postgres.Dialector。
-
pgx的healthCheckPeriod默认关闭,线上建议开启(如 30s),自动踢掉失效连接 - PostgreSQL 的
tcp_keepalive参数(如keepalives=1)应设在 DSN 中,防长连接被中间设备断开 - 别依赖 GORM 的
Config.SkipDefaultTransaction来“省资源”——它只跳过事务 wrapper,不影响连接池行为










