4. AutoMigrate 入门:基本用法与自动表结构管理
AutoMigrate 是 GORM 提供的最便捷的数据库迁移入口。它不需要编写任何 DDL 语句,只需定义好 Go 结构体,调用 AutoMigrate 方法即可自动完成表的创建与字段同步。本章将围绕其基本用法、自动建表与自动更新表结构三个核心场景展开,帮助你快速建立对 AutoMigrate 的直观认知。
4.1 AutoMigrate 核心机制
AutoMigrate 本质上是一个“增量同步”工具。它读取结构体字段定义,与数据库中已有表结构进行对比,然后执行必要的 ALTER TABLE 或 CREATE TABLE 操作。它不会删除已有字段或表,也不会修改字段类型(除非显式配置)。
4.2 基本用法:一行代码完成迁移
在 GORM 中,调用 AutoMigrate 只需要传入一个或多个结构体指针。以下是最简示例:
package main
import (
"gorm.io/driver/sqlite"
"gorm.io/gorm"
)
type User struct {
ID uint
Name string
Age int
}
func main() {
db, err := gorm.Open(sqlite.Open("test.db"), &gorm.Config{})
if err != nil {
panic("failed to connect database")
}
// 自动迁移:创建或更新 User 表
db.AutoMigrate(&User{})
}
执行上述代码后,GORM 会自动在数据库中创建 users 表(表名由结构体名自动转为蛇形复数),包含 id、name、age 三个字段。
4.3 自动创建表:从零到表
当数据库中不存在对应表时,AutoMigrate 会执行 CREATE TABLE。下表展示了结构体字段与数据库列的默认映射规则:
| Go 类型 | 数据库列类型(SQLite) | 数据库列类型(MySQL) | 数据库列类型(PostgreSQL) |
|---|---|---|---|
uint / int |
INTEGER | BIGINT UNSIGNED / BIGINT | BIGSERIAL / BIGINT |
string |
TEXT | VARCHAR(255) | TEXT |
bool |
NUMERIC | TINYINT(1) | BOOLEAN |
time.Time |
DATETIME | DATETIME(3) | TIMESTAMP WITH TIME ZONE |
float64 |
REAL | DOUBLE | DOUBLE PRECISION |
gorm:"type:varchar(100)" 自定义列类型,覆盖默认映射。
4.4 自动更新表结构:新增字段与索引
当表已存在,但结构体新增了字段时,AutoMigrate 会自动执行 ALTER TABLE ADD COLUMN。以下示例演示了新增 Email 字段后的迁移行为:
// 假设数据库已有 users 表(id, name, age)
type User struct {
ID uint
Name string
Age int
Email string // 新增字段
}
// 执行迁移
db.AutoMigrate(&User{})
// 数据库 users 表自动增加 email TEXT 列
除了新增列,AutoMigrate 还会自动创建索引(如果结构体字段定义了索引标签):
type Product struct {
Code string `gorm:"uniqueIndex"`
Price uint
}
db.AutoMigrate(&Product{})
// 自动创建 products 表,并为 code 列创建唯一索引
4.5 AutoMigrate 执行流程
下图展示了 AutoMigrate 从结构体到数据库表的完整执行路径:
4.6 多模型迁移与批量操作
AutoMigrate 支持同时传入多个结构体,一次性完成多张表的创建或更新:
type Order struct {
ID uint
UserID uint
Amount float64
CreatedAt time.Time
}
type Payment struct {
ID uint
OrderID uint
Method string
Status string
}
// 批量迁移
db.AutoMigrate(&User{}, &Order{}, &Payment{})
执行后,数据库中会同时存在 users、orders、payments 三张表。如果某张表已存在,则只执行增量变更。
4.7 常见避坑清单
- 字段删除不生效:AutoMigrate 不会删除结构体中已移除的字段。如需删除列,需手动执行
Migrator().DropColumn()。 - 类型变更不生效:将
string改为int不会触发列类型修改。需先手动删除旧列再迁移。 - 表名冲突:默认表名为结构体名的蛇形复数。可通过
TableName()方法自定义表名。 - 外键自动创建:GORM 默认会为
belongs to关系自动创建外键约束,可通过标签gorm:"constraint:OnUpdate:CASCADE,OnDelete:SET NULL;"控制。
NOT NULL 且无默认值,会导致迁移失败。建议先在测试环境验证迁移行为。
4.8 迁移前后对比验证
为了确认 AutoMigrate 是否按预期执行,可以通过 GORM 的 Migrator() 接口进行验证:
// 迁移前检查表是否存在
if db.Migrator().HasTable(&User{}) {
// 检查列是否存在
if db.Migrator().HasColumn(&User{}, "Email") {
println("Email 列已存在,跳过迁移")
} else {
println("Email 列不存在,执行迁移")
db.AutoMigrate(&User{})
}
} else {
println("表不存在,执行创建")
db.AutoMigrate(&User{})
}
这种前置检查方式在冒烟回归测试中非常实用,可以精确控制迁移的执行路径,避免重复操作。