Skip to content

GORM 框架

GORM 是 Go 语言最流行的 ORM 框架,提供了简洁的 API 和强大的功能。

📋 学习目标

  • 理解 ORM 的概念和优势
  • 掌握 GORM 的基本使用
  • 学会模型定义和迁移
  • 掌握 CRUD 操作
  • 理解关联关系处理
  • 学会事务和钩子函数
  • 了解性能优化

🎯 GORM 简介

为什么选择 GORM

  • 功能完整: 支持 CRUD、关联、事务等
  • API 简洁: 链式调用,易于使用
  • 性能优秀: 查询优化,支持预加载
  • 文档完善: 官方文档详细
  • 社区活跃: 使用广泛

安装 GORM

bash
go get -u gorm.io/gorm
go get -u gorm.io/driver/mysql

🚀 快速开始

基本连接

go
package main

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

func main() {
	dsn := "root:password@tcp(127.0.0.1:3306)/mydb?charset=utf8mb4&parseTime=True&loc=Local"
	db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
	if err != nil {
		panic(err)
	}
	
	// 获取底层 sql.DB
	sqlDB, _ := db.DB()
	defer sqlDB.Close()
}

📊 模型定义

基本模型

go
package models

import (
	"time"
	"gorm.io/gorm"
)

type User struct {
	ID        uint           `gorm:"primaryKey" json:"id"`
	Name      string         `gorm:"size:100;not null" json:"name"`
	Email     string         `gorm:"size:100;uniqueIndex;not null" json:"email"`
	Age       int            `gorm:"default:0" json:"age"`
	CreatedAt time.Time      `json:"created_at"`
	UpdatedAt time.Time      `json:"updated_at"`
	DeletedAt gorm.DeletedAt `gorm:"index" json:"deleted_at,omitempty"`
}

模型标签

go
type User struct {
	ID        uint   `gorm:"primaryKey"`              // 主键
	Name      string `gorm:"size:100;not null"`       // 长度限制,非空
	Email     string `gorm:"uniqueIndex"`             // 唯一索引
	Age       int    `gorm:"default:0"`               // 默认值
	Status    string `gorm:"type:enum('active','inactive')"` // 枚举类型
	CreatedAt time.Time                               // 自动时间戳
	UpdatedAt time.Time                               // 自动更新时间
}

自动迁移

go
func main() {
	db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
	if err != nil {
		panic(err)
	}
	
	// 自动迁移
	err = db.AutoMigrate(&User{})
	if err != nil {
		panic(err)
	}
}

🔧 CRUD 操作

创建

go
// 创建单条记录
user := User{Name: "张三", Email: "zhangsan@example.com", Age: 25}
result := db.Create(&user)
if result.Error != nil {
	panic(result.Error)
}

// 批量创建
users := []User{
	{Name: "李四", Email: "lisi@example.com", Age: 30},
	{Name: "王五", Email: "wangwu@example.com", Age: 28},
}
db.Create(&users)

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

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

查询

go
// 查询单条记录
var user User
db.First(&user, 1)                    // 主键查询
db.First(&user, "name = ?", "张三")   // 条件查询

// 查询多条记录
var users []User
db.Find(&users)                       // 查询所有
db.Where("age > ?", 18).Find(&users)  // 条件查询

// 条件查询
db.Where("name = ?", "张三").First(&user)
db.Where("age BETWEEN ? AND ?", 20, 30).Find(&users)
db.Where("name IN ?", []string{"张三", "李四"}).Find(&users)
db.Where("name LIKE ?", "%张%").Find(&users)

// 排序和分页
db.Order("created_at DESC").Limit(10).Offset(0).Find(&users)

// 计数
var count int64
db.Model(&User{}).Where("age > ?", 18).Count(&count)

更新

go
// 更新单条记录
db.Model(&user).Update("name", "李四")
db.Model(&user).Updates(User{Name: "李四", Age: 30})

// 更新多条记录
db.Model(&User{}).Where("age < ?", 18).Update("status", "inactive")

// 更新指定字段
db.Model(&user).Select("name", "age").Updates(User{Name: "李四", Age: 30})

// 忽略字段更新
db.Model(&user).Omit("email").Updates(User{Name: "李四", Email: "new@example.com"})

删除

go
// 软删除
db.Delete(&user)

// 硬删除
db.Unscoped().Delete(&user)

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

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

🔗 关联关系

一对一

go
type User struct {
	ID    uint   `gorm:"primaryKey"`
	Name  string
	Profile Profile `gorm:"foreignKey:UserID"`
}

type Profile struct {
	ID     uint   `gorm:"primaryKey"`
	UserID uint
	Bio    string
	Avatar string
}

// 查询关联
var user User
db.Preload("Profile").First(&user, 1)

一对多

go
type User struct {
	ID     uint   `gorm:"primaryKey"`
	Name   string
	Posts  []Post `gorm:"foreignKey:UserID"`
}

type Post struct {
	ID     uint   `gorm:"primaryKey"`
	UserID uint
	Title  string
	Content string
}

// 查询关联
var user User
db.Preload("Posts").First(&user, 1)

多对多

go
type User struct {
	ID    uint   `gorm:"primaryKey"`
	Name  string
	Roles []Role `gorm:"many2many:user_roles;"`
}

type Role struct {
	ID    uint   `gorm:"primaryKey"`
	Name  string
	Users []User `gorm:"many2many:user_roles;"`
}

// 关联操作
var user User
var role Role
db.First(&user, 1)
db.First(&role, 1)
db.Model(&user).Association("Roles").Append(&role)

🔄 事务

go
// 自动事务
db.Transaction(func(tx *gorm.DB) error {
	if err := tx.Create(&user1).Error; err != nil {
		return err
	}
	
	if err := tx.Create(&user2).Error; err != nil {
		return err
	}
	
	return nil
})

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

if err := tx.Create(&user1).Error; err != nil {
	tx.Rollback()
	return err
}

if err := tx.Create(&user2).Error; err != nil {
	tx.Rollback()
	return err
}

tx.Commit()

🎣 钩子函数

go
type User struct {
	ID        uint
	Name      string
	Email     string
	Password  string
	CreatedAt time.Time
	UpdatedAt time.Time
}

// 创建前钩子
func (u *User) BeforeCreate(tx *gorm.DB) error {
	// 加密密码
	u.Password = hashPassword(u.Password)
	return nil
}

// 创建后钩子
func (u *User) AfterCreate(tx *gorm.DB) error {
	// 发送欢迎邮件
	sendWelcomeEmail(u.Email)
	return nil
}

// 更新前钩子
func (u *User) BeforeUpdate(tx *gorm.DB) error {
	// 更新时间戳
	u.UpdatedAt = time.Now()
	return nil
}

🏃‍♂️ 实践应用

完整的 CRUD 服务

go
package services

import (
	"gorm.io/gorm"
	"myproject/models"
)

type UserService struct {
	db *gorm.DB
}

func NewUserService(db *gorm.DB) *UserService {
	return &UserService{db: db}
}

func (s *UserService) Create(user *models.User) error {
	return s.db.Create(user).Error
}

func (s *UserService) GetByID(id uint) (*models.User, error) {
	var user models.User
	err := s.db.First(&user, id).Error
	if err != nil {
		return nil, err
	}
	return &user, nil
}

func (s *UserService) List(page, pageSize int) ([]models.User, int64, error) {
	var users []models.User
	var total int64
	
	offset := (page - 1) * pageSize
	
	s.db.Model(&models.User{}).Count(&total)
	err := s.db.Offset(offset).Limit(pageSize).Find(&users).Error
	
	return users, total, err
}

func (s *UserService) Update(id uint, user *models.User) error {
	return s.db.Model(&models.User{}).Where("id = ?", id).Updates(user).Error
}

func (s *UserService) Delete(id uint) error {
	return s.db.Delete(&models.User{}, id).Error
}

func (s *UserService) Search(keyword string) ([]models.User, error) {
	var users []models.User
	err := s.db.Where("name LIKE ? OR email LIKE ?", 
		"%"+keyword+"%", "%"+keyword+"%").Find(&users).Error
	return users, err
}

⚠️ 注意事项

1. 性能优化

go
// ✅ 使用预加载避免 N+1 查询
db.Preload("Posts").Find(&users)

// ✅ 使用 Select 指定字段
db.Select("id", "name").Find(&users)

// ✅ 使用索引
db.Model(&User{}).Where("email = ?", email).First(&user)

2. 错误处理

go
// ✅ 检查错误
if err := db.Create(&user).Error; err != nil {
	return err
}

// ✅ 检查记录是否存在
if err := db.First(&user, id).Error; err != nil {
	if errors.Is(err, gorm.ErrRecordNotFound) {
		return fmt.Errorf("用户不存在")
	}
	return err
}

3. 连接池配置

go
sqlDB, _ := db.DB()
sqlDB.SetMaxOpenConns(25)
sqlDB.SetMaxIdleConns(5)
sqlDB.SetConnMaxLifetime(5 * time.Minute)

📚 扩展阅读

⏭️ 下一章节

Go Modules → 学习依赖管理


💡 提示: GORM 是 Go 开发中最常用的 ORM 框架,掌握它对于 Web 开发非常重要!

基于 VitePress 构建