GORM v2连接MySQL最常见问题是gorm.Open第一个参数类型错误,必须用mysql.Open(dsn)返回的Dialector,而非字符串DSN;DSN须含parseTime=True&loc=Local,否则time.Time字段解析失败或时区错乱。

gorm.Open 传参格式不对,连不上 MySQL
最常见问题是 gorm.Open 的第一个参数类型写错。GORM v2 不再接受字符串 DSN,必须用对应数据库的驱动实例(比如 mysql.Open)作为参数。直接传 DSN 字符串会报 unsupported driver: root:pass@tcp(127.0.0.1:3306)/test 这类错误。
正确做法是先导入 gorm.io/driver/mysql,再用它的 mysql.Open 包装 DSN:
import (
"gorm.io/driver/mysql"
"gorm.io/gorm"
)
dsn := "root:password@tcp(127.0.0.1:3306)/test?charset=utf8mb4&parseTime=True&loc=Local"
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
- DSN 中
parseTime=True是必须的,否则time.Time字段会扫描失败 -
loc=Local避免时区错乱,尤其当 MySQL server 端用 UTC 但应用本地时区不一致时 - 密码含特殊字符(如 @ / ?)要 URL 编码,否则 DSN 解析出错
连接池配置没设,高并发下秒变超时
GORM 默认的连接池非常保守(最大连接数 10,空闲连接数 1),压测或真实业务中很容易卡在 dial tcp 127.0.0.1:3306: connect: cannot assign requested address 或 context deadline exceeded。
必须手动配置底层 *sql.DB 实例:
立即学习“go语言免费学习笔记(深入)”;
sqlDB, err := db.DB()
if err != nil {
panic(err)
}
sqlDB.SetMaxOpenConns(100)
sqlDB.SetMaxIdleConns(20)
sqlDB.SetConnMaxLifetime(time.Hour)
-
SetMaxOpenConns建议设为 QPS × 平均查询耗时(秒),例如 500 QPS × 0.2s ≈ 100 -
SetMaxIdleConns通常设为SetMaxOpenConns的 1/5 到 1/3,避免空闲连接长期占用资源 -
SetConnMaxLifetime推荐 1 小时以内,防止 MySQL 的wait_timeout主动断连导致 stale connection
事务里嵌套调用没传 *gorm.DB,数据丢了还不报错
GORM 的事务对象是值类型,db.Transaction(...) 回调里拿到的 tx 是新实例。如果在里面又调用普通 db.Create(...)(而非 tx.Create(...)),操作会走默认连接池,脱离事务上下文——提交时看似成功,其实没进事务,回滚也无效。
典型错误写法:
db.Transaction(func(tx *gorm.DB) error {
tx.Create(&user) // ✅ 正确:用 tx
db.Create(&log) // ❌ 错误:用的是外部 db,不在事务内
return nil
})
- 所有数据库操作必须显式使用传入的
tx变量 - 若需复用已有函数,应让它们接收
*gorm.DB参数,而不是硬编码全局db - 事务内不要混用
db.Session(&gorm.Session{...}),Session 不继承事务状态
迁移时 autoMigrate 报错 “Error 1071: Specified key was too long”
MySQL 5.7 默认 utf8mb4 + InnoDB 的索引长度限制是 767 字节,而 autoMigrate 给 string 字段加唯一索引时,若没指定长度(如 type User struct { Name string `gorm:"unique"` }),GORM 会按字段最大可能长度建索引(utf8mb4 下 varchar(255) → 1020 字节),直接触发该错误。
解决方式只有两个:
- 给字段加长度约束:
Name string `gorm:"type:varchar(191);unique"`(191×4=764 - 改 MySQL 配置:启用
innodb_large_prefix并把行格式设为DYNAMIC,但这需要 DBA 权限且不兼容老版本
开发期建议统一加 varchar(191),上线前再根据实际业务长度优化。
字符集和排序规则也要显式声明,避免依赖 MySQL 默认值:在 DSN 加 &collation=utf8mb4_unicode_ci,或建表时用 db.Migrator().CreateTable(&User{}) 前设置 gorm.ModifyColumn。


















