automigrate没建表或报“relation does not exist”是因为gorm未识别模型:传值而非指针、字段未导出、db未就绪、schema不匹配或类型变更未显式标注。

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 取决于标签写法和驱动能力:
-
Age int→Age int64:默认不升级类型!必须加gorm:"type:bigint",否则库中仍是INT -
Name string→Name string `gorm:"size:100"`:MySQL 通常生效;PostgreSQL 很可能跳过,需显式写gorm:"columnType:varchar(100)" -
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")主动确认关键结构是否就位 - 批量迁移时漏掉中间表:比如只跑了
AutoMigrate(&User{}, &Role{}),却忘了&UserRole{},外键关系永远建不上 - 字段改名或删字段后仍依赖旧结构:GORM 从不删字段、不改名、不降级
NOT NULL,这些操作必须靠Migrator().DropColumn()、RenameColumn()等显式调用
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











