622 字
3 分钟
迁移与初始化

GORM 迁移与初始化#

AutoMigrate#

学习和开发阶段可以使用:

if err := db.AutoMigrate(
&User{},
&Profile{},
&Order{},
); err != nil {
return err
}

AutoMigrate 会根据模型创建表、缺失字段、索引和约束,并尽量安全地调整结构;它不是完整的版本化迁移系统,不负责任意删除字段或自动完成所有破坏性变更。

生产环境不要在每次应用启动时无条件依赖 AutoMigrate 完成复杂变更。结构变更应经过评审、备份、灰度和回滚方案。

Migrator#

migrator := db.Migrator()
exists := migrator.HasTable(&User{})
if !exists {
if err := migrator.CreateTable(&User{}); err != nil {
return err
}
}
if err := migrator.AddColumn(&User{}, "Nickname"); err != nil {
return err
}

常用能力包括:

migrator.HasTable(&User{})
migrator.HasColumn(&User{}, "Email")
migrator.HasIndex(&User{}, "idx_users_email")
migrator.RenameColumn(&User{}, "Name", "DisplayName")
migrator.DropColumn(&User{}, "LegacyField")

DropColumn、重命名和类型变化都可能造成数据损失或锁表,不能只看 Go 代码是否能执行。

应用启动顺序#

读取配置
-> 创建 GORM 连接
-> Ping 数据库
-> 执行已审核的迁移
-> 注册 Repository/Service
-> 启动 Gin HTTP 服务

迁移失败时应用通常应该停止启动,而不是继续对一个结构不确定的数据库提供流量。

种子数据#

种子数据应该具备幂等性:

var role Role
result := db.Where("name = ?", "admin").First(&role)
if errors.Is(result.Error, gorm.ErrRecordNotFound) {
return db.Create(&Role{Name: "admin"}).Error
}
return result.Error

不要把每次启动都会重复插入的演示数据带入生产启动流程。初始化数据、测试夹具和业务数据导入应分开管理。

版本化迁移策略#

当项目需要可审计、可回滚、可按版本执行的迁移时,建议:

  • 将每次结构变更写成有版本号的 SQL 或迁移文件。
  • 迁移在发布流程中单独执行,并记录已执行版本。
  • 应用代码兼容旧结构和新结构,采用 expand/contract 方式逐步变更。
  • 先新增字段和双写,再回填数据,最后切换读路径并删除旧结构。
  • 大表变更评估锁表时间、在线 DDL、复制延迟和回滚成本。

GORM 的模型定义可以作为迁移意图,但不应替代生产数据库变更评审。

外键与约束#

是否由 GORM 创建外键约束,应结合团队迁移方式、数据库规范和历史表结构决定。关闭约束创建不等于取消数据完整性要求,应用和数据库至少要有一层承担约束责任。

官方资料#

迁移与初始化
https://shirone.mysqil.com/posts/gorm/迁移与初始化/
作者
HikariTish
发布于
2026-07-30
许可协议
CC BY-NC-SA 4.0

分享文章

生成精美分享图或复制链接,与更多人分享本文。

继续阅读

沿着主题读

基于共同的标签与分类

换条路线

从其他文章中稳定抽取