automigrate 按需建表或修改结构,首次运行创建表,后续对比差异执行 add column/create index 等操作,不删字段或改不兼容类型;依赖 gorm 标签精准控制字段定义;需显式传入所有模型;生产环境应避免直接使用,且不处理数据迁移。

AutoMigrate 会建表,但只在需要时建
它不是“每次运行都重建”,而是先检查表是否存在、字段是否匹配,再决定是 CREATE TABLE 还是 ALTER TABLE。所以你改完结构体后多跑几次 AutoMigrate,不会报错,也不会丢数据——前提是没删字段或改非兼容类型。
- 首次运行:表不存在 → 自动建表(含主键、索引、外键)
- 后续运行:对比结构体与现有表 → 缺字段就
ADD COLUMN,缺索引就CREATE INDEX,字段类型可扩(如varchar(50)→varchar(100))就改,但不会缩容或删列 - SQLite 等不支持
ALTER COLUMN的数据库,GORM 会走“重建表 + 拷贝数据 + 删旧表”流程,此时必须保证有写权限且磁盘空间充足
字段标签写错,表就建不对
很多“建了表但字段没生效”“唯一约束没加上”的问题,其实出在结构体标签上。GORM 不靠注释或命名约定,全靠 gorm: 标签驱动建表逻辑。
-
ID uint `gorm:"primaryKey"`—— 没这行,GORM 默认用id字段当主键,但如果你字段名是ID却没标primaryKey,它可能当成普通字段,导致建表失败或无主键 -
Email string `gorm:"uniqueIndex"`—— 写成"unique"只加约束,不建索引;写成"index"不带唯一性;只有"uniqueIndex"才既建唯一约束又建索引 -
Name string `gorm:"size:100"`—— MySQL 下生成varchar(100);不写默认是varchar(255);但 SQLite 忽略size,一律当 text 处理
多个模型一起迁移,顺序无关但得显式传入
AutoMigrate 不会自动扫描所有结构体,你传谁,它就管谁。漏传一个,对应表就不会被创建或更新。
- 正确:
db.AutoMigrate(&User{}, &Order{}, &Product{})—— 一次搞定三张表 - 错误:
db.AutoMigrate(&User{})后忘了加&Order{},那 order 表永远不出现 - 注意:外键依赖关系不影响执行顺序(GORM 会自动解析),但如果你在
User里写了Orders []Order `gorm:"foreignKey:UserID"`,而Order模型没传进AutoMigrate,外键列user_id仍会建,只是不会加外键约束(除非你关了DisableForeignKeyConstraintWhenMigrating)
生产环境别直接用 AutoMigrate
它适合开发和测试阶段快速对齐结构,但在生产库上直接跑,风险在于:没有回滚、无法预览 SQL、不支持字段重命名或类型收缩。一旦出错,只能手动救。
- MySQL 8+ 支持
RENAME COLUMN,但 GORM 默认不开(需配DontSupportRenameColumn: false);MariaDB 或旧版 MySQL 会静默跳过重命名,导致字段“看着存在,实际没生效” - 想加个
NOT NULL字段?如果表里已有数据,AutoMigrate会失败(因 MySQL 要求提供默认值),得先加可空字段,再用Migrator().AlterColumn补约束 - 真正稳妥的做法:用
db.Migrator()手动控制,比如db.Migrator().HasColumn(&User{}, "vip_level")先判断,再决定调AddColumn还是跳过
最常被忽略的一点:AutoMigrate 不处理数据迁移。加了新字段,老记录那列就是 NULL 或零值——业务代码得自己兜底。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











