直接用gorm.open连mysql必须配置dsn含parsetime=true&loc=local,否则time.time字段解析失败panic;还需通过db.db()设置连接池参数并调用ping()验证连通性。

直接用 gorm.Open 连 MySQL,不配 DSN 参数和连接池,90% 概率启动就 panic 或运行中随机报错。
DSN 字符串必须带 parseTime=True 和 loc=Local
MySQL 返回的时间字段(如 created_at)默认是字节切片,GORM 不会自动转成 time.Time。漏掉这两个参数,Find 或 Scan 时大概率触发 cannot scan into *time.Time panic。
-
parseTime=True:告诉 MySQL 驱动把时间字段解析为 Go 的time.Time -
loc=Local:避免存的是北京时间、查出来变成 UTC;生产环境建议统一设为loc=Asia/Shanghai -
charset=utf8mb4:必须显式指定,否则 emoji 或四字节字符写入失败或乱码 - 完整示例:
"root:pass@tcp(127.0.0.1:3306)/test?charset=utf8mb4&parseTime=True&loc=Local"(注意&是 HTML 实体,代码里写&)
mysql.Open(dsn) 是函数调用,不是传类型或结构体
常见错误是把 mysql.Open 当成构造器,传 mysql.New() 或 &mysql.Config{},结果编译失败或运行 panic。
- ✅ 正确写法:
gorm.Open(mysql.Open(dsn), &gorm.Config{}) - ❌ 错误写法:
gorm.Open(mysql.New(), ...)(mysql.New是 v1 废弃 API) - ❌ 错误写法:
gorm.Open(&mysql.Config{DSN: dsn}, ...)(类型不匹配,*mysql.Config不是gorm.Dialector) - 如需自定义驱动行为(比如禁用外键),要包在
mysql.Config{}里再传给mysql.Open:mysql.Open(mysql.Config{DSN: dsn, DisableForeignKeyConstraintWhenMigrating: true})
连接池参数必须从 db.DB() 获取底层 *sql.DB 设置
gorm.Config 不控制连接复用,它只管 GORM 层行为(日志、自动迁移等)。真正决定并发建连、空闲保活、连接超时的,是底层 *sql.DB 对象。
- 必须这样链式获取并配置:
sqlDB, _ := db.DB(); sqlDB.SetMaxOpenConns(80); sqlDB.SetMaxIdleConns(20); sqlDB.SetConnMaxLifetime(time.Hour) - 不设
SetMaxIdleConns容易在压测时看到大量dial tcp: lookup xxx: no such host——其实是空闲连接被系统回收后,新请求来不及建连 -
SetConnMaxLifetime建议设为 300 秒(5 分钟),防止 MySQL 的wait_timeout(默认 28800 秒)导致连接僵死 - 上线前务必调用
sqlDB.Stats()打印确认MaxOpenConnections和Idle值是否符合预期
PostgreSQL 连接失败?先检查驱动导入和 sslmode=disable
GORM v2 连 PostgreSQL 报 unsupported driver: postgres 或空指针 panic,基本就是两件事没做对。
- 必须下划线导入驱动:
_ "gorm.io/driver/postgres",否则postgres.Open返回 nil - 本地或内网部署时,
sslmode=disable必须显式加在 DSN 末尾,否则默认走sslmode=require,连不上就卡住 - DSN 缺一不可:
host、port、user、password、dbname,少一个都 panic - 时区建议补上:
TimeZone=Asia/Shanghai,避免时间字段读写偏差
最常被跳过的一步:没在应用启动后调用 db.Ping() 验证连接有效性。DNS 解析失败、防火墙拦截、密码过期等问题,都会在这里暴露。别等接口 500 了才回头查。











