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)会影响所有模型,注意用条件钩子隔离。



