Golang GORM 库

GORM 简介

GORM 是 Go 最流行的 ORM 库,支持 MySQL、PostgreSQL、SQLite、SQL Server 等数据库,提供模型映射、CRUD、关联关系、事务、自动迁移、钩子函数等完整能力。核心特性:

  • 结构体 ↔ 数据表的自动映射;
  • 链式查询构造器;
  • AutoMigrate 自动建表/改表;
  • CRUD 各阶段的钩子函数(Before/After Create/Update/Delete…)。

安装与连接

go get -u gorm.io/gorm
go get -u gorm.io/driver/mysql   // 按数据库选驱动
dsn := "user:password@tcp(127.0.0.1:3306)/dbname?charset=utf8mb4&parseTime=true&loc=Local"
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
if err != nil { log.Fatal(err) }

DSN 里两个参数务必带上:charset=utf8mb4(完整 UTF-8 支持,emoji 也存得下)、parseTime=true(时间字段解析为 time.Time)。

模型定义

type User struct {
    ID        uint      `gorm:"primaryKey"`
    Name      string    `gorm:"size:255"`
    Email     string    `gorm:"uniqueIndex"`
    CreatedAt time.Time
    UpdatedAt time.Time
}

// 或用内置模型:gorm.Model 自带 ID/CreatedAt/UpdatedAt/DeletedAt
type Post struct {
    gorm.Model
    Title string
}

// 自定义表名
func (User) TableName() string { return "users" }

基本 CRUD

// 创建
user := User{Name: "John", Email: "john@example.com"}
if err := db.Create(&user).Error; err != nil { log.Fatal(err) }

// 查询
var user User
db.First(&user)                      // 第一条
db.First(&user, 1)                  // 主键=1
db.Where("name = ?", "John").First(&user)
var users []User
db.Find(&users)                     // 全部

// 更新(注意 Updates 用结构体时零值字段会被忽略)
db.Model(&user).Update("Name", "Jane")
db.Model(&user).Updates(User{Name: "Jane"})

// 删除(软删除:有 DeletedAt 字段时默认软删除)
db.Delete(&user)

关联与预加载

支持 Has One / Has Many / Belongs To / Many To Many。查询关联数据务必用预加载避免 N+1 查询

db.Preload("Profile").First(&user)   // 一次查询关联,而不是循环里逐个查

事务与钩子

tx := db.Begin()
if err := tx.Create(&a).Error; err != nil {
    tx.Rollback()
    return err
}
if err := tx.Create(&b).Error; err != nil {
    tx.Rollback()
    return err
}
tx.Commit()

钩子函数(BeforeSave/AfterCreate 等)注册在模型方法上,适合统一处理创建时间、生成 ID 等逻辑。

自动迁移

db.AutoMigrate(&User{}, &Post{})

开发期方便;生产环境建议用迁移工具管理 schema,避免 AutoMigrate 的隐式行为。

性能优化建议

  • 批量插入用 CreateInBatches(如 db.CreateInBatches(users, 100)),避免逐条 INSERT;
  • 写入时用 Select/Omit 控制字段,避免写入不必要的列;
  • 列表接口限制返回字段,配合 Limit/Offset 分页;
  • 对热点查询用 FindInBatches 流式处理大数据集。

常见坑

  • Updates 结构体忽略零值:想更新零值字段要用 map[string]interface{}Select 指定;
  • 软删除:带 DeletedAt 的模型 Delete 默认软删除,唯一索引会与历史软删除记录冲突——解决:用部分唯一索引或改用硬删除;
  • 全局条件:链式调用的条件会累积,忘了加 Session(&gorm.Session{NewDB: true}) 可能带出脏条件;
  • 回调污染:注册了全局钩子(如自动填充 ID)会影响所有模型,注意用条件钩子隔离。
滚动至顶部