GORM V2必须用gorm.io/driver/mysql下划线导入,DSN须含parseTime=True&loc=Local,否则time.Time字段为零值;AutoMigrate仅新增表/字段/索引,不删改字段类型。

gorm.Open 不能直接用旧版驱动或错配 DSN,否则连接会静默失败或 panic。
用对驱动:gorm.io/driver/mysql 是唯一推荐路径
github.com/jinzhu/gorm(v1)和 gorm.io/gorm(v2)完全不兼容,混用会导致 invalid driver name 或连接无报错但 db.Ping() 失败。
必须按版本严格匹配驱动:
- GORM v2 → 必须用 gorm.io/driver/mysql,且用下划线导入
- GORM v1 → 只能用 github.com/go-sql-driver/mysql(注意不是 github.com/jinzhu/gorm/dialects/mysql,后者已废弃)
常见错误:
- 在 v2 项目里 import
_ "github.com/go-sql-driver/mysql"→ 连接成功但后续查询全返回空或 panic - 没加下划线导入(如
"gorm.io/driver/mysql"而非_ "gorm.io/driver/mysql")→failed to initialize driver: unknown driver "mysql"
DSN 必须含 parseTime=True&loc=Local
MySQL 的DATETIME / TIMESTAMP 字段默认被 GORM 当作字符串读取,不加参数会导致 time.Time 字段始终为零值。
正确 DSN 示例:
root:pass@tcp(127.0.0.1:3306)/test?charset=utf8mb4&parseTime=True&loc=Local关键点: -
parseTime=True:启用 time.Time 解析(注意大小写,true 或 1 无效)
- loc=Local:避免时区错位(若服务与 MySQL 时区一致,用 loc=Asia/Shanghai 更稳妥)
- charset=utf8mb4:必须显式指定,否则 emoji、四字节 UTF-8 字符写入失败
漏掉 parseTime=True 的典型现象:结构体中 CreatedAt time.Time 字段始终是 0001-01-01 00:00:00 +0000 UTC。
连接前务必校验配置字段非空
生产环境最常踩的坑不是语法,而是 DSN 由配置文件注入时字段为空: -v.GetString("db.host") 返回空字符串 → DSN 变成 @tcp(:)/ → 报错 dial tcp: unknown port tcp/
- 密码含特殊字符(如 @、/)未 URL 编码 → DSN 解析中断
建议初始化时做显式检查:
立即学习“go语言免费学习笔记(深入)”;
if host == "" || port == "" || user == "" || dbname == "" {
return fmt.Errorf("missing required db config: host=%q, port=%q, user=%q, dbname=%q", host, port, user, dbname)
}
dsn := fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=utf8mb4&parseTime=True&loc=Local", user, password, host, port, dbname)AutoMigrate 不会删字段,也不更新字段类型
db.AutoMigrate(&User{}) 只做三件事:建表(如不存在)、加缺失字段、加缺失索引。
它不会:
- 删除已存在但结构体中已移除的字段
- 修改已有字段的类型(比如把 string 改成 *string,数据库列仍是 VARCHAR)
- 更改字段约束(如新增 NOT NULL 标签,不会给原列加约束)
所以字段变更后,得手动执行 SQL 或用迁移工具(如 gormigrate),不能只靠 AutoMigrate。
真正容易被忽略的是:GORM v2 的 gorm.Open 返回的是 <em>gorm.DB</em>,但它底层依赖 sql.DB;你必须立刻调用 db.DB().SetMaxOpenConns() 等设置连接池,否则高并发下会耗尽 MySQL 连接数——这问题不会在本地测试暴露,只在线上突发超时。


















