gorm 的 automigrate 仅执行安全的增量同步,不删除字段或索引、不支持回滚;需显式传入导出结构体,确保连接成功后调用,并注意数据库类型差异与外键配置。

GORM 的 AutoMigrate 不是“建表脚本生成器”,它只做增量同步,且不会删除字段或索引——想靠它回滚结构变更?不行。
为什么 AutoMigrate 没建出表?
最常见原因是没调用 AutoMigrate,或者调用时传入的结构体没被正确注册(比如定义在未导入的包里)。GORM 不会自动扫描所有 struct,必须显式传进去。
- 确保调用位置在数据库连接成功之后,例如
db.AutoMigrate(&User{}, &Order{}) - 结构体必须是导出的(首字母大写),且字段也需导出才能映射
- 如果用了
TableName()方法自定义表名,确认返回值不为空字符串、不含非法字符 - PostgreSQL 用户注意:默认 schema 是
public,如用其他 schema 需设置search_path或在TableName()中包含 schema 名(如"my_schema.users")
AutoMigrate 会改哪些东西?
它只做「安全的向上兼容」操作:添加缺失的表、新增字段、添加缺失的索引、扩展字段长度(如从 VARCHAR(10) 到 VARCHAR(255))。但以下操作它一律跳过:
- 字段类型变更(如
int→string) - 字段重命名(旧字段保留,新字段新增)
- 删除字段或索引
- 修改 NOT NULL 约束(已有 NULL 数据时加 NOT NULL 会失败)
- MySQL 的
ENGINE或CHARSET变更(除非显式用gorm:clause_options)
也就是说,AutoMigrate 不是 ALTER TABLE 全能代理,它更像一个“结构对齐检查器”。
如何让 AutoMigrate 支持外键和约束?
GORM 默认不创建外键(尤其是 SQLite 和 MySQL 的某些版本),必须显式启用:
- MySQL:初始化时加
gorm.Config{DisableForeignKeyConstraintWhenMigrating: false} - PostgreSQL:外键默认启用,但关联字段类型必须严格一致(如
UserID uint对应ID uint,不能是int) - 用
foreignKey和constraint标签控制行为,例如:type Order struct { ID uint `gorm:"primaryKey"` UserID uint `gorm:"index;not null;foreignKey:ID;constraint:OnUpdate:CASCADE,OnDelete:SET NULL;"` User User `gorm:"foreignKey:UserID"` } - 注意:PostgreSQL 的
ON DELETE SET NULL要求字段允许 NULL,否则迁移报错ERROR: column "user_id" is not nullable
真正麻烦的是跨环境一致性——开发用 SQLite 自动迁移没问题,上线到 PostgreSQL 却因类型映射差异(如 bool → BOOLEAN vs TINYINT)或权限限制失败。别依赖 AutoMigrate 打通所有环境,关键服务还是得配 SQL 迁移文件 + 显式版本控制。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











