GORM连接数据库需显式导入驱动、调用gorm.Open并配置连接池,否则易现连接耗尽或unknown driver错误;因gorm.Open仅初始化不建连,首次查询才触发连接,若驱动未注册则panic。

GORM 连接数据库不是“配好 DSN 就完事”,必须显式导入驱动、调用 gorm.Open、并手动配置连接池,否则上线后大概率出现连接耗尽或 driver: unknown driver 错误。
为什么 gorm.Open 调用后不报错,但查数据时 panic?
因为 gorm.Open 只初始化配置,并不真正建连;首次执行 db.First、db.Find 等操作时才触发底层 sql.DB.conn 建连。若此时驱动没注册,就会炸出 driver: unknown driver "mysql" 或 "postgres"。
- 必须在 import 中显式加下划线导入驱动:
_ "gorm.io/driver/mysql"或_ "gorm.io/driver/postgres" - 别用旧版
github.com/jinzhu/gorm—— 它的驱动导入路径和新版不兼容,容易漏注册 - DSN 里带错参数(比如把
parseTime=True写成parsetime=true)不会让Open报错,但后续时间字段解析会失败
MySQL 和 PostgreSQL 的 DSN 关键差异点
两个库的 DSN 格式表面相似,但参数名、默认行为、SSL 处理完全不同,混用必出问题。
- MySQL DSN 示例:
root:pass@tcp(127.0.0.1:3306)/mydb?charset=utf8mb4&parseTime=True&loc=Local&timeout=5s - PostgreSQL DSN 示例:
host=localhost port=5432 user=myuser password=mypass dbname=mydb sslmode=disable TimeZone=Asia/Shanghai -
sslmode是 PostgreSQL 强制项,MySQL 用tls参数控制(如tls=skip-verify) - MySQL 的
loc=Local对应 PostgreSQL 的TimeZone,但值格式不同(Asia/ShanghaivsLocal)
连接池不设 SetMaxOpenConns 会怎样?
默认最大打开连接数是 0(即无限制),高并发下瞬间打爆数据库,MySQL 报 Too many connections,PG 报 remaining connection slots are reserved for non-replication superuser connections。
- 务必在
gorm.Open后立即设置:db.SetMaxOpenConns(10)、db.SetMaxIdleConns(5)、db.SetConnMaxLifetime(1h) -
SetConnMaxLifetime不是“连接活多久”,而是“连接复用上限”——超时后连接会被主动关闭,避免被 DB 侧 kill 导致i/o timeout - SQLite 等嵌入式库不用设连接池,但 GORM 不会自动识别,仍需手动调用
SetMaxOpenConns(1)避免竞争
多数据库共存时最常踩的坑
用一个全局 map 存多个 *gorm.DB,然后裸着并发读写,不出三天就 panic:fatal error: concurrent map writes。
- 不要:
var dbs = map[string]*gorm.DB{"mysql": mysqlDB, "pg": pgDB} - 要封装成结构体字段,带锁或只读访问:
type DBManager struct { MySQL *gorm.DB; PG *gorm.DB } - 别共享模型结构体跨库用:
db.Table("users").Where(...)在 MySQL 和 PG 上语义不同(比如"user"在 PG 是关键字,在 MySQL 会语法错误) - 事务绝对不能跨库——
mysqlDB.Transaction()和pgDB.Transaction()彼此完全隔离,没有协调机制
真正的难点不在怎么连上,而在连上之后怎么不让连接泄漏、怎么让时区/字符集/SSL 参数在不同环境保持一致、以及怎么安全地在多实例间切换而不污染上下文。这些细节不写进初始化函数里,迟早半夜收告警。











