不会删字段,AutoMigrate仅执行安全“加法”操作:建表、加字段、加索引、加外键;不删字段/表、不改类型、不改约束、不重命名、不降级NOT NULL,生产环境须用版本化迁移工具替代。

AutoMigrate 会删字段吗?
不会删字段,也不会删表、改类型、改约束。GORM 的 AutoMigrate 只做“加法”:新增表、新增字段、新增索引、新增外键(如果数据库支持且模型定义了)。它不会执行 DROP COLUMN 或 ALTER COLUMN TYPE 这类破坏性操作。
这意味着你改了 struct 字段名、删了字段、把 string 改成 int,AutoMigrate 都不会同步这些变更——旧字段原封不动留在数据库里,新字段可能被加上,但数据不迁移,也不校验冲突。
- 字段重命名 → 数据库里留下两个字段(旧的没删,新的加了)
- 删除 struct 字段 → 对应数据库列仍在,只是 GORM 不再读写它
- 修改字段类型(如
string→int)→AutoMigrate通常静默跳过,或报错(取决于驱动和数据库),绝不会自动转换数据
什么时候该用 AutoMigrate?
适合本地开发快速对齐模型与空库,或 CI 环境每次跑测试前重置 schema;不适合生产环境直接调用。
典型安全场景:AutoMigrate 在应用启动时执行,且数据库是全新或已知干净(比如测试库),同时你确认没有历史数据需要兼容。
立即学习“go语言免费学习笔记(深入)”;
- 开发机 SQLite / 本地 PostgreSQL 新建项目:可以放心用
- 测试用内存 DB(如
sqlite:file::memory:):推荐每次启动都调用 - 生产 MySQL/PostgreSQL:禁止在上线流程中依赖
AutoMigrate做结构更新 - 已有用户数据的表:哪怕只加一个非空字段(没设默认值),
AutoMigrate也可能失败
生产环境怎么安全同步结构变更?
必须用显式迁移(migrations),而不是依赖 AutoMigrate。GORM 官方推荐搭配 gorm.io/gorm/migrator 手动控制,或更主流的是用独立迁移工具,比如 golang-migrate/migrate + SQL 文件。
关键点不是“谁来执行 ALTER”,而是“谁来保证顺序、回滚、幂等、人工审核”——AutoMigrate 全都不提供。
- 每个变更写一个带版本号的 SQL 文件(如
20240520_add_user_status.up.sql) - 用
migrateCLI 或嵌入到代码中按序执行,失败即停 - 上线前在预发库跑一遍,检查执行耗时、锁表时间、索引构建影响
- 涉及数据迁移(如拆分字段、状态码映射)必须写 Go 脚本,不能只靠 DDL
为什么 Model 加了 gorm:"default:0" 却没生效?
因为 AutoMigrate 只在**首次创建字段时**应用 default 约束;后续给已有字段加 default 标签,它不会补 ALTER COLUMN SET DEFAULT。
更隐蔽的问题:MySQL 中 default:"0" 和 default:0 行为不同(前者是字符串,后者是数字),PostgreSQL 对 NULL 默认值也更敏感。而且部分驱动(如 mysql)在 AutoMigrate 时根本忽略 default,只靠建表语句里的 DEFAULT 关键字。
- 新表字段:default 标签一般能落到 DDL 里(但需看驱动实现)
- 已有表加 default:必须手写
ALTER TABLE ... ALTER COLUMN ... SET DEFAULT ... - 想确保行为一致:别依赖标签,用 SQL 迁移文件明确定义 default
- 注意
gorm:"default:null"在多数数据库不合法,要用gorm:"default:nil"或留空
AutoMigrate 当成“一键同步工具”塞进 main 函数,结果某次发布悄悄加了个字段,又悄悄漏掉了 NOT NULL 约束,导致后续插入全跪——它不报错,只沉默。


















