Go 用 GORM 做 CRUD 实战:模型定义、关联预加载与钩子

test12026-09-261 次阅读

连接数据库与模型定义

GORM 是 Go 里最主流的 ORM,用结构体标签描述表结构,AutoMigrate 可以自动建表或增量加字段。下面用一个用户和订单的场景演示。

type User struct {
    ID        uint      `gorm:"primaryKey"`
    Name      string    `gorm:"size:64;index"`
    Email     string    `gorm:"uniqueIndex"`
    CreatedAt time.Time
    Orders    []Order   // 一对多关联
}

type Order struct {
    ID     uint   `gorm:"primaryKey"`
    UserID uint   `gorm:"index"`
    Amount int
    Status string `gorm:"default:pending"`
}

db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
if err != nil {
    log.Fatal(err)
}
db.AutoMigrate(&User{}, &Order{})

常规 CRUD

// 创建
u := User{Name: "张三", Email: "z@a.com"}
db.Create(&u)

// 查询
var user User
db.First(&user, u.ID)              // 按主键
db.Where("name = ?", "张三").First(&user)

// 更新(只改非零字段)
db.Model(&user).Updates(User{Name: "李四"})

// 删除
db.Delete(&user)

关联预加载

默认查询不会带出关联数据,忘记预加载又在循环里逐条查就会触发 N+1。用 Preload 一次性把关联拉出来。

var users []User
db.Preload("Orders").Find(&users)
for _, u := range users {
    fmt.Printf("%s 有 %d 个订单\n", u.Name, len(u.Orders))
}

如果只要已支付的订单,可以传条件:db.Preload("Orders", "status = ?", "paid")。深层关联用点号:Preload("Orders.Items")。

钩子(Hooks)

GORM 在增删改查的各个时点回调特定方法名,适合做密码哈希、默认值、缓存失效等。

func (u *User) BeforeCreate(tx *gorm.DB) error {
    if u.Email == "" {
        return errors.New("email 不能为空")
    }
    return nil
}

func (u *User) AfterFind(tx *gorm.DB) error {
    // 查出后脱敏,或补一个不在表里的计算字段
    return nil
}

工程建议

  • 生产环境开启 PrepareStmt 提升重复语句性能,并配合连接池。
  • 写操作尽量用事务包起来,db.Transaction(func(tx *gorm.DB) error {...}) 自动提交或回滚。
  • 复杂联表或聚合用 db.Raw / Joins 更直观,不必强求全部 ORM 化。
T

test1

文章作者

连接数据库与模型定义 GORM 是 Go 里最主流的 ORM,用结构体标签描述表结构,AutoMigrate 可以自动...

分类
技术
发布时间
2026-09-26
字数
约 1587 字
阅读
1 次