2. AutoMigrate 基础:自动建表、增字段与索引
AutoMigrate 是 GORM 提供的最便捷的数据库 Schema 同步工具。它根据 Go 结构体(Model)的定义,自动创建表、添加缺失的字段和索引,而不会删除或修改已有列的类型。本章将深入讲解 AutoMigrate 的基本用法、执行时机以及它在开发与生产环境中的适用边界。
2.1 AutoMigrate 核心机制
AutoMigrate 本质上是一个“增量同步”工具。它读取结构体字段定义,与数据库中现有表结构进行对比,然后执行 ALTER TABLE 语句来补齐差异。它不会删除任何列或改变列的数据类型,因此相对安全。
| 行为 | 支持 | 说明 |
|---|---|---|
| 创建新表 | ✅ | 表不存在时,根据结构体生成 CREATE TABLE |
| 添加新字段 | ✅ | 检测到结构体新增字段,执行 ALTER TABLE ADD COLUMN |
| 添加索引 | ✅ | 检测到新索引标签,执行 CREATE INDEX |
| 修改字段类型 | ❌ | 不会执行,需手动迁移或使用 Migrator |
| 删除字段/索引 | ❌ | 不会执行,需手动 DROP |
2.2 基本用法与自动建表
在项目初始化阶段,通常将 AutoMigrate 放在数据库连接之后、业务启动之前。以下是最基本的调用方式:
import (
"gorm.io/gorm"
"gorm.io/driver/sqlite"
)
type User struct {
gorm.Model
Name string
Email string `gorm:"uniqueIndex"`
Age int
}
func main() {
db, err := gorm.Open(sqlite.Open("test.db"), &gorm.Config{})
if err != nil {
panic("failed to connect database")
}
// 自动迁移 —— 创建表、添加字段和索引
err = db.AutoMigrate(&User{})
if err != nil {
panic("migration failed")
}
}
执行上述代码后,GORM 会在数据库中生成一张名为 users 的表,包含 id、created_at、updated_at、deleted_at、name、email、age 七个字段,并在 email 列上创建唯一索引。
TableName() 方法自定义。
2.3 自动增加字段
当业务迭代需要给已有表添加新字段时,只需在结构体中增加字段定义,再次调用 AutoMigrate 即可。
// 假设 users 表已存在,现在需要增加 Phone 字段
type User struct {
gorm.Model
Name string
Email string `gorm:"uniqueIndex"`
Age int
Phone string `gorm:"default:'unknown'"` // 新增字段
}
// 再次执行迁移
db.AutoMigrate(&User{})
GORM 会自动执行 ALTER TABLE users ADD COLUMN phone TEXT DEFAULT 'unknown'。已有数据行的新字段会被填充为默认值。
ALTER TABLE ADD COLUMN 不支持设置 NOT NULL 且无默认值的字段。建议新增字段时始终提供合理的默认值或允许为空。
2.4 自动增加索引
索引通过结构体标签 gorm:"index" 或 gorm:"uniqueIndex" 声明。AutoMigrate 会自动检测新增的索引标签并创建对应的数据库索引。
type Product struct {
gorm.Model
Code string `gorm:"index"` // 普通索引
Price uint `gorm:"index:idx_price"` // 自定义索引名
SKU string `gorm:"uniqueIndex"` // 唯一索引
}
db.AutoMigrate(&Product{})
上述代码会创建三个索引:
idx_products_code—— 普通索引idx_price—— 自定义名称的普通索引idx_products_sku—— 唯一索引
2.5 AutoMigrate 执行流程
下图展示了 AutoMigrate 从结构体解析到数据库执行的完整链路:
2.6 多表迁移与批量执行
AutoMigrate 支持同时传入多个模型,按顺序依次执行迁移:
db.AutoMigrate(&User{}, &Product{}, &Order{})
也可以使用 ...interface{} 切片动态传入:
models := []interface{}{&User{}, &Product{}, &Order{}}
db.AutoMigrate(models...)
2.7 生产环境使用建议
AutoMigrate 虽然便捷,但在生产环境中需要谨慎使用。以下表格总结了不同场景下的推荐策略:
| 环境 | 推荐策略 | 原因 |
|---|---|---|
| 开发/测试 | ✅ 直接使用 AutoMigrate | 快速迭代,无需手动维护 DDL |
| 生产(小表) | ⚠️ 谨慎使用,建议配合备份 | ALTER 操作可能锁表,影响读写 |
| 生产(大表) | ❌ 使用版本化迁移工具 | 需要控制变更顺序、回滚、灰度 |
2.8 常见陷阱与避坑
- 字段类型变更无效: 将
string改为int不会生效,需手动ALTER COLUMN。 - 索引重命名不生效: 修改索引名不会自动删除旧索引,需手动清理。
- 外键约束: AutoMigrate 默认不创建外键,需通过标签
constraint显式声明。 - 并发迁移: 多个实例同时启动可能导致冲突,建议加锁或串行化。
2.9 本章小结
AutoMigrate 是 GORM 迁移体系的基石,适用于开发阶段的快速原型和中小型项目的持续集成。它通过“只增不改”的策略降低了误操作风险,但无法替代专业的版本化迁移工具。掌握 AutoMigrate 的边界和用法,是后续学习契约校验和高级迁移模式的前提。