Gin 不处理数据库连接,需用 GORM 等 ORM;连不上 MySQL 主因是 DSN 缺 parseTime=True、loc=Local、charset=utf8mb4,且 gorm.Open 必须传 mysql.Open(dsn);PostgreSQL 需导入驱动并设 sslmode=disable。

Gin 本身不处理数据库连接,所有 DB 操作都依赖你选的驱动和 ORM(比如 GORM)——直接用 gorm.Open 却连不上,90% 是 DSN、驱动导入或连接池配置没对齐。
DSN 字符串必须带 parseTime=True 和 loc=Local
MySQL 返回的时间字段(如 created_at)默认是 []uint8,GORM 不会自动转成 time.Time,漏掉这两个参数,Find 或 Scan 时大概率 panic:cannot scan into *time.Time。
-
parseTime=True:告诉 MySQL 驱动把时间字段解析为 Go 的time.Time -
loc=Local:避免时区错乱(比如存的是北京时间,查出来变成 UTC) -
charset=utf8mb4:必须显式指定,否则 emoji 或四字节字符会乱码 - 完整示例:
"root:pass@tcp(127.0.0.1:3306)/test?charset=utf8mb4&parseTime=True&loc=Local"(注意 URL 中的&要保留,别误转义)
gorm.Open 第一个参数必须是 mysql.Open(dsn)
GORM v2 要求第一个参数是 gorm.Dialector 类型,而只有 mysql.Open(dsn) 才返回合法的 Dialector。常见错误写法会导致编译失败或运行时 panic。
- ✅ 正确:
gorm.Open(mysql.Open(dsn), &gorm.Config{}) - ❌ 错误:
gorm.Open(mysql.New(), ...)(mysql.New是 v1 写法,v2 已废弃) - ❌ 错误:
gorm.Open(&mysql.Config{DSN: dsn}, ...)(类型不匹配,*mysql.Config不是Dialector) - 如需自定义驱动行为(例如禁用外键),要包在
mysql.Config{}里再传给mysql.Open:mysql.Open(mysql.Config{DSN: dsn, DisableForeignKeyConstraintWhenMigrating: true})
连接池参数必须调用 db.DB().SetMaxOpenConns 等方法
gorm.Config 只控制 GORM 层行为(日志、自动迁移等),不管理底层连接池。真正决定连接复用、超时、回收的是 *sql.DB 对象。
- 必须显式获取:
sqlDB, _ := db.DB(),然后设置: -
sqlDB.SetMaxOpenConns(100)(防并发打满) -
sqlDB.SetMaxIdleConns(20)(不设容易在压测时看到dial tcp: lookup xxx: no such host——其实是空闲连接被系统回收后新请求来不及建连) -
sqlDB.SetConnMaxLifetime(300 * time.Second)(建议 5 分钟,避免 MySQL 的wait_timeout杀死僵死连接)
PostgreSQL 连接失败?先检查驱动导入和 sslmode=disable
绝大多数 PostgreSQL 连接 panic 是因为驱动没导入或 DSN 缺关键参数。GORM v2 要求显式下划线导入驱动:_ "gorm.io/driver/postgres",否则 postgres.Open 返回 nil,gorm.Open 直接 panic。
- 错误现象:
failed to connect database: failed to initialize database, got error unsupported driver: postgres或空指针 panic - DSN 必须包含:
host、port、user、password、dbname,缺一不可 - 本地开发务必加
sslmode=disable,否则默认走ssl=required,连不上就卡住 - 时区建议加
TimeZone=Asia/Shanghai,避免时间字段写入/查询偏差
最常被忽略的是:连接对象不能在每次 HTTP 请求里重新 gorm.Open —— GORM 实例是线程安全的,应该全局初始化一次;还有事务开始后忘了 Commit() 或 Rollback(),会导致连接挂起甚至锁表。


















