跳到主要内容

GORM

GORM (Go Object-Relational Mapping) 是 Go 语言中最流行的 ORM 库,提供了强大的数据库操作功能,支持 MySQL、PostgreSQL、SQLite、SQL Server 等多种数据库。

简介

GORM 特性

GORM 核心特性:

  • 全功能 ORM: 关联、钩子、批量操作、预加载等
  • 关联关系: Has One、Has Many、Many To Many、多态、单表继承
  • 自动迁移: 自动保持数据库结构同步
  • 链式调用: 流畅的 API 设计
  • SQL 构建: 灵活的 SQL 查询构建器
  • 性能优化: 连接池、预加载、批量操作
  • 多数据库: 支持 MySQL、PostgreSQL、SQLite、SQL Server
  • 钩子函数: Before/After Create/Update/Find/Delete
  • 插件系统: 支持自定义插件

适用场景:

  • Web 应用数据库操作
  • 微服务数据访问层
  • 复杂查询场景
  • 数据迁移工具
  • 数据分析应用

安装 GORM

# 安装 GORM
go get -u gorm.io/gorm

# 安装数据库驱动(以 MySQL 为例)
go get -u gorm.io/driver/mysql

# PostgreSQL
go get -u gorm.io/driver/postgres

# SQLite
go get -u gorm.io/driver/sqlite

# SQL Server
go get -u gorm.io/driver/sqlserver

快速开始

package main

import (
"gorm.io/driver/mysql"
"gorm.io/gorm"
"log"
)

type User struct {
ID uint `gorm:"primaryKey"`
Name string `gorm:"size:255"`
Email string `gorm:"size:255;uniqueIndex"`
Age int
}

func main() {
// 连接数据库
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)
}

// 自动迁移
db.AutoMigrate(&User{})

// 创建记录
user := User{Name: "Alice", Email: "alice@example.com", Age: 25}
db.Create(&user)

// 查询记录
var result User
db.First(&result, 1) // 根据 ID 查询

log.Printf("User: %+v\n", result)
}

模型定义

1. 模型结构

type User struct {
ID uint `gorm:"primaryKey"`
CreatedAt time.Time `gorm:"autoCreateTime"`
UpdatedAt time.Time `gorm:"autoUpdateTime"`
DeletedAt gorm.DeletedAt `gorm:"index"`

Name string `gorm:"size:255;not null"`
Email string `gorm:"size:255;uniqueIndex;not null"`
Age int `gorm:"default:0"`
Active bool `gorm:"default:true"`
Balance float64 `gorm:"type:decimal(10,2)"`
Birthday *time.Time
}

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

2. 字段标签

type User struct {
// 主键
ID uint `gorm:"primaryKey"`

// 字段名
Name string `gorm:"column:user_name"`

// 字段类型
Age int `gorm:"type:int"`

// 字段大小
Email string `gorm:"size:255"`

// 默认值
Active bool `gorm:"default:true"`

// 非空
Name string `gorm:"not null"`

// 唯一索引
Email string `gorm:"uniqueIndex"`

// 索引
Name string `gorm:"index"`

// 多个索引
Name string `gorm:"index:idx_user_name"`

// 自动创建时间
CreatedAt time.Time `gorm:"autoCreateTime"`

// 自动更新时间
UpdatedAt time.Time `gorm:"autoUpdateTime"`

// 忽略字段
Temp string `gorm:"-"`

// 嵌入字段
gorm.Model
}

3. 关联关系

一对一 (Has One)

type User struct {
gorm.Model
Name string
CreditCard CreditCard // has one
}

type CreditCard struct {
gorm.Model
Number string
UserID uint // 外键
User User // belongs to
}

一对多 (Has Many)

type User struct {
gorm.Model
Name string
Posts []Post // has many
}

type Post struct {
gorm.Model
Title string
UserID uint // 外键
User User // belongs to
}

多对多 (Many To Many)

type User struct {
gorm.Model
Name string
Languages []Language `gorm:"many2many:user_languages;"`
}

type Language struct {
gorm.Model
Name string
Users []User `gorm:"many2many:user_languages;"`
}

CRUD 操作

1. 创建记录

// 创建单条记录
user := User{Name: "Alice", Email: "alice@example.com", Age: 25}
db.Create(&user)

// 批量创建
users := []User{
{Name: "Alice", Email: "alice@example.com"},
{Name: "Bob", Email: "bob@example.com"},
}
db.Create(&users)

// 使用 CreateInBatches
db.CreateInBatches(users, 100)

// 指定字段创建
db.Select("Name", "Email").Create(&user)

// 忽略字段创建
db.Omit("Age").Create(&user)

// 使用 Map 创建
db.Model(&User{}).Create(map[string]interface{}{
"Name": "Alice",
"Email": "alice@example.com",
})

2. 查询记录

// 查询单条记录
var user User
db.First(&user) // SELECT * FROM users ORDER BY id LIMIT 1

db.Take(&user) // SELECT * FROM users LIMIT 1

db.Last(&user) // SELECT * FROM users ORDER BY id DESC LIMIT 1

// 根据 ID 查询
db.First(&user, 1)

// 根据条件查询
db.First(&user, "name = ?", "Alice")

// 查询多条记录
var users []User
db.Find(&users) // SELECT * FROM users

// 条件查询
db.Where("name = ?", "Alice").Find(&users)

db.Where("name LIKE ?", "%Alice%").Find(&users)

db.Where("age >= ?", 18).Find(&users)

// 多条件查询
db.Where("name = ? AND age >= ?", "Alice", 18).Find(&users)

// In 查询
db.Where("name IN ?", []string{"Alice", "Bob"}).Find(&users)

// Or 查询
db.Where("role = ?", "admin").Or("role = ?", "super_admin").Find(&users)

// 排序
db.Order("age desc").Find(&users)

// 限制
db.Limit(10).Find(&users)

// 偏移
db.Offset(10).Limit(10).Find(&users)

// 计数
var count int64
db.Model(&User{}).Count(&count)
db.Where("name = ?", "Alice").Count(&count)

// 选择字段
db.Select("name", "email").Find(&users)

// 去重
db.Distinct("name").Find(&users)

3. 更新记录

// 保存所有字段
db.Save(&user)

// 更新单个字段
db.Model(&user).Update("name", "Alice")

// 更新多个字段
db.Model(&user).Updates(User{Name: "Alice", Age: 25})

// 更新选定字段
db.Model(&user).Select("name", "age").Updates(User{Name: "Alice", Age: 25})

// 更新忽略字段
db.Model(&user).Omit("email").Updates(User{Name: "Alice", Age: 25})

// 使用 Map 更新
db.Model(&user).Updates(map[string]interface{}{
"name": "Alice",
"age": 25,
})

// 更新表达式
db.Model(&user).Update("age", gorm.Expr("age + ?", 1))

// 批量更新
db.Model(&User{}).Where("active = ?", true).Update("age", 18)

// 批量更新多字段
db.Model(&User{}).Where("active = ?", true).Updates(User{Age: 18, Active: false})

4. 删除记录

// 删除单条记录
db.Delete(&user) // 软删除

// 根据 ID 删除
db.Delete(&User{}, 1)

// 批量删除
db.Where("age < ?", 18).Delete(&User{})

// 永久删除
db.Unscoped().Delete(&user)

// 批量永久删除
db.Unscoped().Where("age < ?", 18).Delete(&User{})

高级查询

1. 预加载 (Preloading)

// 预加载关联
db.Preload("Posts").Find(&users)

// 预加载多级关联
db.Preload("Posts.Comments").Find(&users)

// 条件预加载
db.Preload("Posts", "active = ?", true).Find(&users)

// 多个预加载
db.Preload("Posts").Preload("CreditCard").Find(&users)

// Joins 预加载
db.Joins("Posts").Find(&users)

2. 链式操作

// 链式查询
db.Where("age >= ?", 18).
Where("active = ?", true).
Order("created_at desc").
Limit(10).
Find(&users)

// 子查询
db.Where("age > ?", db.Model(&User{}).Select("AVG(age)")).Find(&users)

// Group By
db.Model(&User{}).Select("name, count(*) as count").Group("name").Find(&results)

// Having
db.Model(&User{}).Select("name, count(*) as count").
Group("name").
Having("count > ?", 1).
Find(&results)

3. 原生 SQL

// 执行原生 SQL
db.Raw("SELECT * FROM users WHERE name = ?", "Alice").Scan(&users)

// 执行原生 SQL 创建
db.Exec("UPDATE users SET name = ? WHERE id = ?", "Alice", 1)

// 命名参数
db.Raw("SELECT * FROM users WHERE name = @name", sql.Named("name", "Alice")).Scan(&users)

// Rows 返回
rows, err := db.Model(&User{}).Where("age > ?", 18).Rows()
defer rows.Close()

for rows.Next() {
var user User
db.ScanRows(rows, &user)
}

钩子函数

type User struct {
gorm.Model
Name string
Email string
}

// 创建前
func (u *User) BeforeCreate(tx *gorm.DB) error {
log.Println("Before Create")
return nil
}

// 创建后
func (u *User) AfterCreate(tx *gorm.DB) error {
log.Println("After Create")
return nil
}

// 更新前
func (u *User) BeforeUpdate(tx *gorm.DB) error {
log.Println("Before Update")
return nil
}

// 更新后
func (u *User) AfterUpdate(tx *gorm.DB) error {
log.Println("After Update")
return nil
}

// 删除前
func (u *User) BeforeDelete(tx *gorm.DB) error {
log.Println("Before Delete")
return nil
}

// 删除后
func (u *User) AfterDelete(tx *gorm.DB) error {
log.Println("After Delete")
return nil
}

// 查询后
func (u *User) AfterFind(tx *gorm.DB) error {
log.Println("After Find")
return nil
}

事务

// 自动事务
db.Transaction(func(tx *gorm.DB) error {
if err := tx.Create(&User{Name: "Alice"}).Error; err != nil {
return err // 回滚
}

if err := tx.Create(&Post{Title: "Hello"}).Error; err != nil {
return err // 回滚
}

return nil // 提交
})

// 手动事务
tx := db.Begin()
defer func() {
if r := recover(); r != nil {
tx.Rollback()
}
}()

if err := tx.Create(&User{Name: "Alice"}).Error; err != nil {
tx.Rollback()
return err
}

if err := tx.Create(&Post{Title: "Hello"}).Error; err != nil {
tx.Rollback()
return err
}

tx.Commit()

迁移

// 自动迁移
db.AutoMigrate(&User{}, &Post{}, &Comment{})

// 创建表
db.Migrator().CreateTable(&User{})

// 删除表
db.Migrator().DropTable(&User{})

// 检查表是否存在
db.Migrator().HasTable(&User{})

// 重命名表
db.Migrator().RenameTable(&User{}, &Users{})

// 添加字段
db.Migrator().AddColumn(&User{}, "email")

// 删除字段
db.Migrator().DropColumn(&User{}, "email")

// 修改字段类型
db.Migrator().AlterColumn(&User{}, "name")

// 创建索引
db.Migrator().CreateIndex(&User{}, "email")

// 删除索引
db.Migrator().DropIndex(&User{}, "email")

性能优化

1. 连接池配置

import (
"gorm.io/driver/mysql"
"gorm.io/gorm"
)

sqlDB, err := db.DB()
if err != nil {
panic(err)
}

// 设置空闲连接池
sqlDB.SetMaxIdleConns(10)

// 设置最大连接数
sqlDB.SetMaxOpenConns(100)

// 设置连接最大存活时间
sqlDB.SetConnMaxLifetime(time.Hour)

2. 批量操作

// 批量插入
var users []User
for i := 0; i < 100; i++ {
users = append(users, User{Name: fmt.Sprintf("user%d", i)})
}

db.CreateInBatches(users, 50)

3. 预加载优化

// 避免 N+1 查询
db.Preload("Posts").Find(&users)

// 使用 Joins
db.Joins("LEFT JOIN posts ON posts.user_id = users.id").Find(&users)

实战示例

完整 CRUD 应用

package main

import (
"gorm.io/driver/mysql"
"gorm.io/gorm"
"log"
"time"
)

type User struct {
ID uint `gorm:"primaryKey"`
CreatedAt time.Time `gorm:"autoCreateTime"`
UpdatedAt time.Time `gorm:"autoUpdateTime"`
DeletedAt gorm.DeletedAt `gorm:"index"`

Name string `gorm:"size:255;not null"`
Email string `gorm:"size:255;uniqueIndex;not null"`
Age int `gorm:"default:0"`
}

func main() {
dsn := "root:password@tcp(127.0.0.1:3306)/testdb?charset=utf8mb4&parseTime=True&loc=Local"
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
if err != nil {
log.Fatal(err)
}

// 自动迁移
db.AutoMigrate(&User{})

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

// 查询
var result User
if err := db.First(&result, user.ID).Error; err != nil {
log.Fatal(err)
}
log.Printf("Found user: %+v\n", result)

// 更新
if err := db.Model(&result).Update("age", 26).Error; err != nil {
log.Fatal(err)
}

// 删除
if err := db.Delete(&result).Error; err != nil {
log.Fatal(err)
}

log.Println("CRUD operations completed successfully")
}

最佳实践

1. 错误处理

result := db.Create(&user)
if result.Error != nil {
log.Fatal(result.Error)
}

if result.RowsAffected == 0 {
log.Println("No rows affected")
}

2. 使用上下文

import "context"

ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()

db.WithContext(ctx).Find(&users)

3. 使用日志

db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{
Logger: logger.Default.LogMode(logger.Info),
})

// 自定义日志
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{
Logger: logger.New(
log.New(os.Stdout, "\r\n", log.LstdFlags),
logger.Config{
SlowThreshold: time.Second,
LogLevel: logger.Info,
Colorful: true,
},
),
})

总结

GORM 是一个功能强大、易于使用的 ORM 框架,提供了丰富的功能和优秀的性能。它支持多种数据库、提供了灵活的查询 API、自动迁移、关联关系处理等功能,使得 Go 语言数据库操作变得简单高效。掌握 GORM 对于 Go Web 开发者来说是非常重要的。

参考资料