automigrate只同步表结构,不迁移数据;它仅执行安全ddl(如建表、加字段、扩类型、加索引/外键),从不生成dml,不删字段、不改字段名、不降not null,且无版本记录与回滚能力。

AutoMigrate 不会迁移数据,只同步表结构 —— 它不碰任何已有行,也不执行 INSERT/UPDATE/DELETE。
AutoMigrate 为什么不会动数据
它本质是“结构对齐器”,不是“数据迁移工具”。所有字段增删、类型扩缩、索引加减都只走 DDL(CREATE TABLE、ADD COLUMN、MODIFY COLUMN 等),从不生成 DML。即使你把 Name string 改成 Name *string,它只会改列的 NULL 约束,绝不会把原来非空的值设为 NULL。
- 想初始化测试数据?用 seed 脚本,别塞进
.up.sql或AutoMigrate调用里 - 想把旧字段数据转到新字段?得自己写
db.Exec("UPDATE ..."),AutoMigrate不负责 - 删了结构体字段(比如
Age int),数据库里age列照常存在,且无任何提示
哪些结构变更会被 AutoMigrate 执行
它只做数据库驱动支持 + GORM 认为“安全”的操作:
- 建表:首次调用
AutoMigrate(&User{})时创建users表 - 加字段:结构体新增
Email string→ 执行ALTER TABLE users ADD COLUMN email VARCHAR(255) - 扩类型:从
gorm:"size:100"改成gorm:"size:255"→ 多数驱动支持MODIFY COLUMN - 加索引/外键:字段带
gorm:"uniqueIndex"或gorm:"foreignKey:UserID",且初始化时设了DisableForeignKeyConstraintWhenMigrating: false - 改 NOT NULL:字段从
string改成*string,GORM 会尝试去掉NOT NULL(取决于驱动)
注意:AutoMigrate 对 SQLite 或 MySQL 5.7 之前版本可能重建整张表(无事务),大表慎用。
常见静默失败场景
它不报错、不打印、不告诉你“什么都没做”——这是最危险的默认行为:
-
AutoMigrate(&User{})没反应?先检查是不是传了User{}而非&User{}(必须是指针) - 外键没生效?确认初始化 DB 时加了
DisableForeignKeyConstraintWhenMigrating: false - 中间表(如
UserRole)没建?GORM 绝不自动生成,必须显式定义 struct 并调AutoMigrate(&UserRole{}) - 索引名重复(如两个字段都标
gorm:"index")?它静默跳过,不会报错也不会覆盖
上线前务必主动验证:db.Migrator().HasTable(&User{}) 和 db.Migrator().HasColumn(&User{}, "email")。
生产环境绝对不能只靠 AutoMigrate
它没有版本记录、无法回滚、不控锁、不保证执行顺序。线上改结构必须用 golang-migrate 这类 CLI 工具管理 SQL 文件:
- 已有库上线前,先
migrate status查当前版本,再migrate force 1校准起点 - 每个
.up.sql只放一条 DDL,禁用USE database_name - Go 程序内调
m.Up()必须加context.WithTimeout,并区分migrate.ErrNoChange和migrate.ErrLocked - MySQL 上 DDL 不在事务中,
.up.sql失败不会触发.down.sql,得人工介入
最易被忽略的一点:AutoMigrate 在开发机跑通 ≠ 生产库结构一致 —— 它不校验、不记录、不告警,脱节是常态,不是例外。











