automigrate仅安全补全结构:建表、加字段、扩长度、加索引/外键;不删字段、不改名、不降级not null。未建表或报“relation does not exist”主因是未传结构体指针、字段未导出、db未就绪、schema不匹配或类型变更未显式标注。

AutoMigrate 不是“一键同步”,它只在安全前提下补全结构:建表、加字段、扩长度、加索引/外键;删字段、改字段名、降级 NOT NULL 一律不干。
为什么 AutoMigrate 没建表或报 “relation does not exist”
根本不是 GORM 不会建,而是它压根没“看到”你的模型。常见原因:
- 传了
User{}而不是&User{}——AutoMigrate必须接收指针才能读取 struct tag - 字段首字母小写(如
name string),Go 不导出,GORM 直接忽略,表里自然没这列 - 数据库连接未就绪:
db是nil,或Open后没调Ping(),AutoMigrate静默失败甚至 panic - PostgreSQL 下 schema 不是
public(比如用了search_path=my_schema),但 DSN 没配,表建在public,查询却去别处找
字段类型变更为什么经常不生效
GORM 默认不做破坏性变更,类型改动是否触发 ALTER COLUMN 取决于标签写法和驱动能力:
-
Name string `gorm:"size:50"`→ 改成size:100:MySQL 通常生效,PostgreSQL 很可能跳过(需显式加columnType:varchar(100)) -
Age int→Age int64:默认不升级类型!必须加gorm:"type:bigint",否则库中仍是INT -
Age int→Age *int(允许 NULL):GORM 会尝试改NOT NULL为可空,但前提是驱动支持且你没关外键开关 - SQLite 或 MySQL 5.7 以前:不支持
RENAME COLUMN,GORM 会重建表(无事务、大表危险),建议初始化时加DontSupportRenameColumn: true
外键、索引、中间表怎么正确配置
默认全关闭,不是 bug,是 GORM 的保守设计。要让它们生效,必须手动开闸、配对打标:
- 外键默认禁用:初始化
gorm.Config时必须设DisableForeignKeyConstraintWhenMigrating: false -
UserID uint不等于外键 —— 必须配合关联字段写User User `gorm:"foreignKey:UserID"`,否则约束不会生成 - 唯一索引直接写
Email string `gorm:"uniqueIndex"`;复合索引用同名index标签:Name string `gorm:"index:idx_user_name_age"`+Age int `gorm:"index:idx_user_name_age"` - 多对多中间表(如
UserRole)GORM 绝对不自动生成,必须自己定义 struct,并显式调db.AutoMigrate(&UserRole{})
生产环境迁移前最易被忽略的三件事
AutoMigrate 永远不会告诉你“这次什么都没做”。它静默跳过所有它认为无需操作的情况——而这恰恰是线上事故的温床:
- 上线前不验证:用
db.Migrator().HasTable(&User{})和db.Migrator().HasColumn(&User{}, "email")主动确认关键结构已就位 - 字段改了但忘了跑迁移:开发改完 struct 就提交,CI/CD 流水线没自动触发
AutoMigrate,导致新字段查不到 - 跨环境差异:本地 MySQL 8,测试环境 MySQL 5.7,同一段
size标签行为不同,重建表风险被低估
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











