1 介绍
1.1 简介
01.ORM框架
a.框架定位
a.对象关系映射
a.核心概念
GORM是Go语言最流行的ORM库
将数据库表映射为Go结构体
提供类型安全的数据库操作
支持完整的CRUD功能
b.技术优势
减少SQL编写工作量
自动处理关联关系
提高开发效率
降低SQL注入风险
b.数据库支持
a.多数据库
MySQL、PostgreSQL、SQLite
SQL Server、TiDB、ClickHouse
统一API接口
易于切换数据库
b.驱动实现
官方驱动支持完善
社区驱动丰富
易于扩展新数据库
插件化架构设计
b.核心特性
a.全功能ORM
a.CRUD操作
Create、Read、Update、Delete
批量操作支持
链式调用API
事务支持
b.高级查询
复杂条件查询
子查询支持
聚合函数
原生SQL支持
b.关联关系
a.关系类型
一对一、一对多
多对多、多态关联
自动预加载
级联操作
b.关联处理
Preload预加载
Joins连接查询
Association关联操作
自动创建关联
c.设计理念
a.开发友好
a.简单易用
直观的API设计
丰富的文档和示例
快速上手
活跃的社��支持
b.类型安全
Go结构体映射
编译期检查
减少运行时错误
IDE友好
b.功能完整
a.企业级特性
事务支持
钩子函数
插件系统
迁移工具
d.版本管理
a.v2稳定版
a.重大改进
重写核心代码
性能大幅提升
API更加简洁
更好的错误处理
b.向后兼容
提供迁移指南
支持渐进式升级
社区活跃支持
持续维护更新
1.2 核心特性
01.CRUD操作
a.Create创建
a.基础创建
// 定义模型
type User struct {
ID uint `gorm:"primaryKey"`
Name string `gorm:"size:100;not null"`
Email string `gorm:"uniqueIndex;not null"`
Age int `gorm:"default:0"`
CreatedAt time.Time
UpdatedAt time.Time
}
// 创建记录
user := User{Name: "Alice", Email: "[email protected] ", Age: 25}
result := db.Create(&user)
if result.Error != nil {
log.Fatal(result.Error)
}
fmt.Printf("Created user ID: %d\n", user.ID)
fmt.Printf("Rows affected: %d\n", result.RowsAffected)
// 批量创建
users := []User{
{Name: "Bob", Email: "[email protected] "},
{Name: "Charlie", Email: "[email protected] "},
}
db.Create(&users)
b.选择字段创建
// 只插入指定字段
db.Select("Name", "Email").Create(&user)
// 排除指定字段
db.Omit("Age").Create(&user)
b.Read查询
a.基础查询
// 查询单条记录
var user User
db.First(&user, 1) // 根据主键查询
db.First(&user, "email = ?", "[email protected] ") // 条件查询
// 查询所有记录
var users []User
db.Find(&users)
// 条件查询
db.Where("age > ?", 18).Find(&users)
db.Where("name IN ?", []string{"Alice", "Bob"}).Find(&users)
// 链式查询
db.Where("age > ?", 18).
Where("email LIKE ?", "%@example.com").
Order("created_at desc").
Limit(10).
Offset(0).
Find(&users)
// 查询指定字段
db.Select("name", "email").Find(&users)
// 统计数量
var count int64
db.Model(&User{}).Where("age > ?", 18).Count(&count)
b.高级查询
// 使用结构体查询
db.Where(&User{Name: "Alice", Age: 25}).Find(&users)
// 使用Map查询
db.Where(map[string]interface{}{"name": "Alice", "age": 25}).Find(&users)
// Not条件
db.Not("name = ?", "Alice").Find(&users)
// Or条件
db.Where("name = ?", "Alice").Or("age > ?", 30).Find(&users)
c.Update更新
a.更新记录
// 更新单个字段
db.Model(&user).Update("name", "Alice Updated")
// 更新多个字段
db.Model(&user).Updates(User{Name: "Alice", Age: 26})
db.Model(&user).Updates(map[string]interface{}{
"name": "Alice",
"age": 26,
})
// 批量更新
db.Model(&User{}).Where("age < ?", 18).Update("status", "minor")
// 更新表达式
db.Model(&User{}).Where("id = ?", 1).Update("age", gorm.Expr("age + ?", 1))
b.Save方法
// Save会保存所有字段
user.Name = "New Name"
db.Save(&user)
// UpdateColumn跳过钩子
db.Model(&user).UpdateColumn("name", "New")
d.Delete删除
a.删除记录
// 删除单条记录
db.Delete(&user, 1) // 根据主键删除
// 条件删除
db.Where("age < ?", 18).Delete(&User{})
// 软删除(需要DeletedAt字段)
type User struct {
ID uint
Name string
DeletedAt gorm.DeletedAt `gorm:"index"`
}
db.Delete(&user) // 软删除,设置DeletedAt
// 永久删除
db.Unscoped().Delete(&user)
// 查询包含软删除的记录
db.Unscoped().Where("age > ?", 18).Find(&users)
b.批量删除
// 批量删除
db.Where("age < ?", 18).Delete(&User{})
db.Delete(&User{}, []int{1, 2, 3})
02.关联关系
a.一对一
a.Has One
// 定义模型
type User struct {
ID uint
Name string
Profile Profile
}
type Profile struct {
ID uint
UserID uint
Bio string
}
// 创建关联
user := User{
Name: "Alice",
Profile: Profile{Bio: "Developer"},
}
db.Create(&user)
// 预加载
var user User
db.Preload("Profile").First(&user, 1)
fmt.Println(user.Profile.Bio)
b.Belongs To
// 多对一关联
type User struct {
ID uint
CompanyID uint
Company Company
}
type Company struct {
ID uint
Name string
}
// 预加载
db.Preload("Company").Find(&users)
b.一对多
a.Has Many
// 定义模型
type User struct {
ID uint
Name string
Posts []Post
}
type Post struct {
ID uint
UserID uint
Title string
}
// 创建关联
user := User{
Name: "Alice",
Posts: []Post{
{Title: "First Post"},
{Title: "Second Post"},
},
}
db.Create(&user)
// 预加载
var user User
db.Preload("Posts").First(&user, 1)
for _, post := range user.Posts {
fmt.Println(post.Title)
}
b.条件预加载
// 预加载时添加条件
db.Preload("Posts", "status = ?", "published").Find(&users)
// 使用函数预加载
db.Preload("Posts", func(db *gorm.DB) *gorm.DB {
return db.Order("created_at desc").Limit(5)
}).Find(&users)
c.多对多
a.Many To Many
// 定义模型
type User struct {
ID uint
Name string
Roles []Role `gorm:"many2many:user_roles;"`
}
type Role struct {
ID uint
Name string
}
// 创建关联
user := User{
Name: "Alice",
Roles: []Role{
{Name: "Admin"},
{Name: "Editor"},
},
}
db.Create(&user)
// 添加关联
var user User
db.First(&user, 1)
var role Role
db.First(&role, 1)
db.Model(&user).Association("Roles").Append(&role)
// 查询关联
var roles []Role
db.Model(&user).Association("Roles").Find(&roles)
b.自定义中间表
// 自定义中间表字段
type UserRole struct {
UserID uint
RoleID uint
CreatedAt time.Time
}
type User struct {
Roles []Role `gorm:"many2many:user_roles;"`
}
03.查询构建
a.链式API
a.复杂查询
// 链式查询示例
var users []User
db.Where("age > ?", 18).
Where("email LIKE ?", "%@example.com").
Not("name", "Admin").
Or("status = ?", "active").
Order("created_at desc").
Limit(10).
Offset(0).
Find(&users)
// 子查询
subQuery := db.Model(&Order{}).
Select("user_id").
Where("amount > ?", 1000)
db.Where("id IN (?)", subQuery).Find(&users)
// 分组聚合
type Result struct {
Date time.Time
Total int
}
var results []Result
db.Model(&Order{}).
Select("DATE(created_at) as date, SUM(amount) as total").
Group("DATE(created_at)").
Having("SUM(amount) > ?", 1000).
Scan(&results)
b.Scopes作用域
// 定义可复用的查询条件
func ActiveUsers(db *gorm.DB) *gorm.DB {
return db.Where("status = ?", "active")
}
func AdultUsers(db *gorm.DB) *gorm.DB {
return db.Where("age >= ?", 18)
}
// 使用Scopes
db.Scopes(ActiveUsers, AdultUsers).Find(&users)
04.高级特性
a.事务
a.事务处理
// 手动事务
tx := db.Begin()
if err := tx.Create(&user).Error; err != nil {
tx.Rollback()
return err
}
if err := tx.Create(&profile).Error; err != nil {
tx.Rollback()
return err
}
tx.Commit()
// 自动事务
err := db.Transaction(func(tx *gorm.DB) error {
if err := tx.Create(&user).Error; err != nil {
return err
}
if err := tx.Create(&profile).Error; err != nil {
return err
}
return nil
})
b.嵌套事务
// SavePoint保存点
db.Transaction(func(tx *gorm.DB) error {
tx.Create(&user)
tx.SavePoint("sp1")
tx.Create(&order)
tx.RollbackTo("sp1")
return nil
})
b.钩子
a.生命周期钩子
// Before/After钩子
func (u *User) BeforeCreate(tx *gorm.DB) error {
// 创建前执行
u.CreatedAt = time.Now()
u.UUID = uuid.New().String()
return nil
}
func (u *User) AfterCreate(tx *gorm.DB) error {
// 创建后执行
log.Printf("User %s created", u.Name)
return nil
}
func (u *User) BeforeUpdate(tx *gorm.DB) error {
u.UpdatedAt = time.Now()
return nil
}
func (u *User) AfterUpdate(tx *gorm.DB) error {
log.Printf("User %d updated", u.ID)
return nil
}
b.查询钩子
func (u *User) AfterFind(tx *gorm.DB) error {
// 查询后处理
u.Name = strings.ToUpper(u.Name)
return nil
}
1.3 优缺点
01.主要优点
a.功能完整
全功能ORM支持
丰富的关联关系处理
自动预加载功能
完善的事务支持
b.易于使用
API设计直观
文档丰富详细
学习曲线平缓
社区活跃度高
c.生态丰富
插件系统完善
第三方扩展多
工具链完整
持续维护更新
02.主要缺点
a.性能开销
ORM层抽象带来性能损耗
复杂查询性能不如原生SQL
预加载可能产生N+1问题
内存占用相对较高
b.学习成本
高级特性需要深入学习
关联关系配置复杂
错误调试有一定难度
需要理解ORM原理
c.灵活性限制
某些复杂SQL难以实现
性能优化空间有限
数据库特性支持受限
迁移工具功能有限
03.适用场景
a.快速开发
CRUD密集型应用
后台管理系统
API服务开发
MVP原型开发
b.中小型项目
业务逻辑清晰
数据模型稳定
团队规模适中
开发周期紧张
04.不适用场景
a.高性能要求
实时系统
高并发场景
大数据量处理
性能敏感应用
b.复杂SQL
复杂统计查询
多表复杂关联
数据库特定功能
性能优化要求高
1.4 使用场景
01.Web应用开发
a.后台管理系统
a.用户管理模块
// 完整的用户CRUD操作
type User struct {
ID uint `gorm:"primaryKey"`
Username string `gorm:"size:50;uniqueIndex;not null"`
Email string `gorm:"size:100;uniqueIndex;not null"`
Password string `gorm:"size:255;not null"`
Role string `gorm:"size:20;default:'user'"`
Status int `gorm:"default:1;comment:'1:active 0:inactive'"`
CreatedAt time.Time
UpdatedAt time.Time
DeletedAt gorm.DeletedAt `gorm:"index"`
}
// 创建用户
user := User{
Username: "admin",
Email: "[email protected] ",
Password: hashPassword("secret"),
Role: "admin",
}
if err := db.Create(&user).Error; err != nil {
log.Printf("创建用户失败: %v", err)
}
// 分页查询用户列表
var users []User
var total int64
page, pageSize := 1, 20
offset := (page - 1) * pageSize
db.Model(&User{}).Count(&total)
db.Limit(pageSize).Offset(offset).
Order("created_at desc").
Find(&users)
// 条件查询
db.Where("role = ?", "admin").
Where("status = ?", 1).
Find(&users)
// 更新用户信息
db.Model(&user).Updates(map[string]interface{}{
"email": "[email protected] ",
"status": 1,
})
// 软删除
db.Delete(&user, user.ID)
// 恢复软删除
db.Unscoped().Model(&user).Update("deleted_at", nil)
b.权限管理
// 角色权限关联
type Role struct {
ID uint
Name string `gorm:"size:50;uniqueIndex"`
Permissions []Permission `gorm:"many2many:role_permissions;"`
}
type Permission struct {
ID uint
Name string `gorm:"size:50;uniqueIndex"`
Action string `gorm:"size:100"`
}
// 查询用户权限
var user User
db.Preload("Roles.Permissions").First(&user, userID)
// 检查权限
hasPermission := false
for _, role := range user.Roles {
for _, perm := range role.Permissions {
if perm.Action == "user:delete" {
hasPermission = true
break
}
}
}
b.内容管理系统
a.文章管理
type Article struct {
ID uint `gorm:"primaryKey"`
Title string `gorm:"size:200;not null;index"`
Content string `gorm:"type:text"`
AuthorID uint
Author User
CategoryID uint
Category Category
Tags []Tag `gorm:"many2many:article_tags;"`
ViewCount int `gorm:"default:0"`
Status string `gorm:"size:20;default:'draft'"`
PublishedAt *time.Time
CreatedAt time.Time
UpdatedAt time.Time
}
// 创建文章并关联标签
article := Article{
Title: "GORM使用指南",
Content: "详细内容...",
AuthorID: 1,
Tags: []Tag{
{Name: "Go"},
{Name: "ORM"},
},
}
db.Create(&article)
// 复杂查询:预加载关联
var articles []Article
db.Preload("Author").
Preload("Category").
Preload("Tags").
Where("status = ?", "published").
Order("published_at desc").
Limit(10).
Find(&articles)
// 全文搜索
db.Where("title LIKE ? OR content LIKE ?", "%GORM%", "%GORM%").
Find(&articles)
b.评论系统
type Comment struct {
ID uint
ArticleID uint
UserID uint
User User
Content string `gorm:"type:text"`
ParentID *uint
Replies []Comment `gorm:"foreignKey:ParentID"`
CreatedAt time.Time
}
// 查询文章评论(包含回复)
var comments []Comment
db.Where("article_id = ? AND parent_id IS NULL", articleID).
Preload("User").
Preload("Replies.User").
Order("created_at desc").
Find(&comments)
02.API服务开发
a.RESTful API
a.用户API
// Gin框架集成
func GetUsers(c *gin.Context) {
var users []User
page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
pageSize, _ := strconv.Atoi(c.DefaultQuery("page_size", "20"))
var total int64
db.Model(&User{}).Count(&total)
offset := (page - 1) * pageSize
if err := db.Limit(pageSize).Offset(offset).Find(&users).Error; err != nil {
c.JSON(500, gin.H{"error": err.Error()})
return
}
c.JSON(200, gin.H{
"data": users,
"total": total,
"page": page,
})
}
func CreateUser(c *gin.Context) {
var user User
if err := c.ShouldBindJSON(&user); err != nil {
c.JSON(400, gin.H{"error": err.Error()})
return
}
if err := db.Create(&user).Error; err != nil {
c.JSON(500, gin.H{"error": err.Error()})
return
}
c.JSON(201, user)
}
func UpdateUser(c *gin.Context) {
id := c.Param("id")
var user User
if err := db.First(&user, id).Error; err != nil {
c.JSON(404, gin.H{"error": "用户不存在"})
return
}
var updates map[string]interface{}
if err := c.ShouldBindJSON(&updates); err != nil {
c.JSON(400, gin.H{"error": err.Error()})
return
}
db.Model(&user).Updates(updates)
c.JSON(200, user)
}
func DeleteUser(c *gin.Context) {
id := c.Param("id")
if err := db.Delete(&User{}, id).Error; err != nil {
c.JSON(500, gin.H{"error": err.Error()})
return
}
c.JSON(204, nil)
}
b.查询过滤
// 动态查询构建
func ListUsers(c *gin.Context) {
var users []User
query := db.Model(&User{})
// 角色过滤
if role := c.Query("role"); role != "" {
query = query.Where("role = ?", role)
}
// 状态过滤
if status := c.Query("status"); status != "" {
query = query.Where("status = ?", status)
}
// 关键词搜索
if keyword := c.Query("keyword"); keyword != "" {
query = query.Where("username LIKE ? OR email LIKE ?",
"%"+keyword+"%", "%"+keyword+"%")
}
// 日期范围
if startDate := c.Query("start_date"); startDate != "" {
query = query.Where("created_at >= ?", startDate)
}
if endDate := c.Query("end_date"); endDate != "" {
query = query.Where("created_at <= ?", endDate)
}
// 排序
if sort := c.Query("sort"); sort != "" {
query = query.Order(sort)
} else {
query = query.Order("created_at desc")
}
query.Find(&users)
c.JSON(200, users)
}
b.GraphQL API
a.Resolver实现
type Resolver struct {
db *gorm.DB
}
func (r *Resolver) Users(ctx context.Context, args struct {
First *int32
After *string
Filter *UserFilter
}) ([]*User, error) {
query := r.db.Model(&User{})
if args.Filter != nil {
if args.Filter.Role != nil {
query = query.Where("role = ?", *args.Filter.Role)
}
}
var users []*User
if err := query.Find(&users).Error; err != nil {
return nil, err
}
return users, nil
}
03.数据处理任务
a.批量数据导入
a.CSV导入
import "encoding/csv"
func ImportUsersFromCSV(filename string) error {
file, err := os.Open(filename)
if err != nil {
return err
}
defer file.Close()
reader := csv.NewReader(file)
records, err := reader.ReadAll()
if err != nil {
return err
}
var users []User
for i, record := range records {
if i == 0 {
continue // 跳过表头
}
users = append(users, User{
Username: record[0],
Email: record[1],
Role: record[2],
})
}
// 分批插入,避免内存溢出
return db.CreateInBatches(users, 100).Error
}
b.Excel导入
import "github.com/xuri/excelize/v2"
func ImportUsersFromExcel(filename string) error {
f, err := excelize.OpenFile(filename)
if err != nil {
return err
}
defer f.Close()
rows, err := f.GetRows("Sheet1")
if err != nil {
return err
}
var users []User
for i, row := range rows {
if i == 0 {
continue
}
if len(row) >= 3 {
users = append(users, User{
Username: row[0],
Email: row[1],
Role: row[2],
})
}
}
return db.CreateInBatches(users, 100).Error
}
b.数据导出
a.导出CSV
func ExportUsersToCSV(filename string) error {
var users []User
db.Find(&users)
file, err := os.Create(filename)
if err != nil {
return err
}
defer file.Close()
writer := csv.NewWriter(file)
defer writer.Flush()
// 写入表头
writer.Write([]string{"ID", "Username", "Email", "Role"})
// 写入数据
for _, user := range users {
writer.Write([]string{
strconv.Itoa(int(user.ID)),
user.Username,
user.Email,
user.Role,
})
}
return nil
}
c.数据同步
a.定时同步
func SyncDataFromAPI() error {
// 从外部API获取数据
resp, err := http.Get("https://api.example.com/users")
if err != nil {
return err
}
defer resp.Body.Close()
var apiUsers []APIUser
json.NewDecoder(resp.Body).Decode(&apiUsers)
// 使用事务批量更新
return db.Transaction(func(tx *gorm.DB) error {
for _, apiUser := range apiUsers {
var user User
result := tx.Where("external_id = ?", apiUser.ID).First(&user)
if result.Error == gorm.ErrRecordNotFound {
// 创建新记录
user = User{
ExternalID: apiUser.ID,
Username: apiUser.Name,
Email: apiUser.Email,
}
if err := tx.Create(&user).Error; err != nil {
return err
}
} else {
// 更新现有记录
if err := tx.Model(&user).Updates(map[string]interface{}{
"username": apiUser.Name,
"email": apiUser.Email,
}).Error; err != nil {
return err
}
}
}
return nil
})
}
04.快速开发场景
a.MVP原型开发
a.快速搭建
// 自动迁移所有模型
func InitDatabase() error {
return db.AutoMigrate(
&User{},
&Product{},
&Order{},
&OrderItem{},
&Category{},
&Tag{},
)
}
// 初始化测试数据
func SeedData() error {
users := []User{
{Username: "admin", Email: "[email protected] ", Role: "admin"},
{Username: "user1", Email: "[email protected] ", Role: "user"},
}
products := []Product{
{Name: "Product 1", Price: 99.99, Stock: 100},
{Name: "Product 2", Price: 199.99, Stock: 50},
}
return db.Transaction(func(tx *gorm.DB) error {
if err := tx.Create(&users).Error; err != nil {
return err
}
if err := tx.Create(&products).Error; err != nil {
return err
}
return nil
})
}
b.快速迭代
// 灵活的模型调整
type User struct {
ID uint
Username string
Email string
// 新增字段,AutoMigrate会自动添加
Phone string `gorm:"size:20"`
Avatar string `gorm:"size:255"`
}
// 重新运行AutoMigrate即可
db.AutoMigrate(&User{})
b.微服务开发
a.服务间通信
// 订单服务调用用户服务
type OrderService struct {
db *gorm.DB
}
func (s *OrderService) CreateOrder(userID uint, items []OrderItem) error {
// 验证用户
var user User
if err := s.db.First(&user, userID).Error; err != nil {
return errors.New("用户不存在")
}
// 创建订单
order := Order{
UserID: userID,
Items: items,
Status: "pending",
}
return s.db.Transaction(func(tx *gorm.DB) error {
if err := tx.Create(&order).Error; err != nil {
return err
}
// 更新库存
for _, item := range items {
if err := tx.Model(&Product{}).
Where("id = ?", item.ProductID).
Update("stock", gorm.Expr("stock - ?", item.Quantity)).
Error; err != nil {
return err
}
}
return nil
})
}
1.5 快速开始
01.安装配置
a.安装GORM
go get -u gorm.io/gorm
go get -u gorm.io/driver/mysql
02.数据库连接
a.MySQL连接
import (
"gorm.io/driver/mysql"
"gorm.io/gorm"
)
dsn := "user:pass@tcp(127.0.0.1:3306)/dbname?charset=utf8mb4&parseTime=True"
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
03.模型定义
a.基础模型
type User struct {
ID uint `gorm:"primaryKey"`
Name string `gorm:"size:100"`
Email string `gorm:"uniqueIndex"`
CreatedAt time.Time
}
04.基础操作
a.CRUD示例
db.Create(&user) // 创建
db.First(&user, 1) // 查询
db.Model(&user).Update("name", "New") // 更新
db.Delete(&user) // 删除
1.6 数据库连接
01.连接字符串
a.DSN配置
// MySQL
dsn := "user:pass@tcp(host:port)/db?charset=utf8mb4&parseTime=True&loc=Local"
// PostgreSQL
dsn := "host=localhost user=gorm password=gorm dbname=gorm port=9920"
// SQLite
dsn := "gorm.db"
02.连接池
a.连接池配置
sqlDB, _ := db.DB()
sqlDB.SetMaxIdleConns(10)
sqlDB.SetMaxOpenConns(100)
sqlDB.SetConnMaxLifetime(time.Hour)
03.多数据库
a.读写分离
db, _ := gorm.Open(mysql.Open(dsn), &gorm.Config{})
db.Use(dbresolver.Register(dbresolver.Config{
Sources: []gorm.Dialector{mysql.Open(writeDSN)},
Replicas: []gorm.Dialector{mysql.Open(readDSN)},
}))
04.连接管理
a.连接检查
sqlDB, _ := db.DB()
err := sqlDB.Ping()
defer sqlDB.Close()
2 模型定义
2.1 汇总:6个
01.模型声明
结构体定义、字段类型、标签、约定
02.字段标签
column、type、size、primaryKey、index
03.主键和索引
主键定义、复合主键、索引创建、唯一索引
04.关联关系
belongs to、has one、has many、many to many
05.嵌入结构
匿名字段、字段继承、公共字段、代码复用
06.模型钩子
BeforeCreate、AfterCreate、生命周期、业务逻辑
2.2 模型声明
01.基础模型
a.结构体定义
type User struct {
gorm.Model
Name string
Email string
}
// gorm.Model包含: ID, CreatedAt, UpdatedAt, DeletedAt
02.字段类型
a.常用类型
type Product struct {
ID uint
Name string
Price float64
Stock int
IsActive bool
Data datatypes.JSON
CreatedAt time.Time
}
03.默认值
a.默认值设置
type User struct {
ID uint
Name string `gorm:"default:guest"`
Age int `gorm:"default:18"`
Status string `gorm:"default:active"`
}
04.字段约束
a.约束定义
type User struct {
Name string `gorm:"not null;size:100"`
Email string `gorm:"uniqueIndex;not null"`
Age int `gorm:"check:age >= 0"`
}
2.3 字段标签
01.column标签
a.字段映射
type User struct {
ID uint `gorm:"column:user_id;primaryKey"`
Name string `gorm:"column:user_name"`
Email string `gorm:"column:email_address"`
}
02.type标签
a.数据类型
type Article struct {
Title string `gorm:"type:varchar(200)"`
Content string `gorm:"type:text"`
Views int `gorm:"type:bigint"`
}
03.size标签
a.字段大小
type User struct {
Name string `gorm:"size:100"`
Password string `gorm:"size:255"`
}
04.其他标签
a.常用标签
type User struct {
ID uint `gorm:"primaryKey;autoIncrement"`
Name string `gorm:"index"`
Email string `gorm:"uniqueIndex"`
}
2.4 主键和索引
01.主键定义
a.主键设置
type User struct {
ID uint `gorm:"primaryKey"`
UUID string `gorm:"type:char(36);primaryKey"`
}
02.复合主键
a.联合主键
type UserRole struct {
UserID uint `gorm:"primaryKey"`
RoleID uint `gorm:"primaryKey"`
}
03.索引创建
a.索引定义
type User struct {
Name string `gorm:"index"`
Email string `gorm:"uniqueIndex"`
Age int `gorm:"index:idx_age"`
}
// 复合索引
type User struct {
Name string `gorm:"index:idx_name_email"`
Email string `gorm:"index:idx_name_email"`
}
04.索引选项
a.索引配置
type User struct {
Name string `gorm:"index:idx_name,unique,priority:1"`
}
2.5 关联关系
01.Belongs To
a.多对一
type User struct {
ID uint
CompanyID uint
Company Company
}
type Company struct {
ID uint
Name string
}
02.Has One
a.一对一
type User struct {
ID uint
Profile Profile
}
type Profile struct {
ID uint
UserID uint
Bio string
}
03.Has Many
a.一对多
type User struct {
ID uint
Orders []Order
}
type Order struct {
ID uint
UserID uint
}
04.Many To Many
a.多对多
type User struct {
ID uint
Roles []Role `gorm:"many2many:user_roles;"`
}
type Role struct {
ID uint
Name string
}
2.6 嵌入结构
01.匿名字段
a.嵌入结构
type BaseModel struct {
ID uint
CreatedAt time.Time
UpdatedAt time.Time
}
type User struct {
BaseModel
Name string
}
02.公共字段
a.时间戳
type User struct {
ID uint
CreatedAt time.Time
UpdatedAt time.Time
DeletedAt gorm.DeletedAt `gorm:"index"`
}
03.gorm.Model
a.标准模型
type User struct {
gorm.Model // 包含 ID, CreatedAt, UpdatedAt, DeletedAt
Name string
Email string
}
04.自定义嵌入
a.审计字段
type AuditModel struct {
CreatedBy uint
UpdatedBy uint
CreatedAt time.Time
UpdatedAt time.Time
}
type Article struct {
AuditModel
Title string
Content string
}
2.7 模型钩子
01.创建钩子
a.BeforeCreate
func (u *User) BeforeCreate(tx *gorm.DB) error {
u.UUID = uuid.New().String()
return nil
}
02.更新钩子
a.BeforeUpdate
func (u *User) BeforeUpdate(tx *gorm.DB) error {
if u.Age < 0 {
return errors.New("age cannot be negative")
}
return nil
}
03.删除钩子
a.BeforeDelete
func (u *User) BeforeDelete(tx *gorm.DB) error {
// 清理关联数据
tx.Where("user_id = ?", u.ID).Delete(&Order{})
return nil
}
04.查询钩子
a.AfterFind
func (u *User) AfterFind(tx *gorm.DB) error {
u.Name = strings.ToUpper(u.Name)
return nil
}
3 CRUD操作
3.1 创建记录
01.Create
a.单条插入
user := User{Name: "Alice", Email: "[email protected] "}
result := db.Create(&user)
fmt.Println(user.ID) // 返回插入的ID
fmt.Println(result.RowsAffected) // 影响行数
02.批量创建
a.批量插入
users := []User{
{Name: "Alice", Email: "[email protected] "},
{Name: "Bob", Email: "[email protected] "},
}
db.Create(&users)
03.选择字段
a.指定字段
db.Select("Name", "Email").Create(&user) // 只插入指定字段
db.Omit("Age").Create(&user) // 排除指定字段
04.冲突处理
a.Upsert
db.Clauses(clause.OnConflict{
Columns: []clause.Column{{Name: "email"}},
DoUpdates: clause.AssignmentColumns([]string{"name"}),
}).Create(&user)
3.2 查询记录
01.First/Last
a.单条查询
var user User
db.First(&user) // 第一条记录
db.First(&user, 10) // 主键为10
db.First(&user, "name = ?", "Alice") // 条件查询
db.Last(&user) // 最后一条记录
02.Find
a.多条查询
var users []User
db.Find(&users) // 查询所有
db.Where("age > ?", 18).Find(&users) // 条件查询
db.Limit(10).Find(&users) // 限制数量
03.Take
a.任意一条
var user User
db.Take(&user) // 获取一条记录,无排序
04.Count
a.计数
var count int64
db.Model(&User{}).Count(&count)
db.Model(&User{}).Where("age > ?", 18).Count(&count)
3.3 更新记录
01.Save
a.全字段更新
user.Name = "New Name"
db.Save(&user) // 更新所有字段
02.Update/Updates
a.��定字段更新
db.Model(&user).Update("name", "New Name") // 单字段
db.Model(&user).Updates(User{Name: "New", Age: 25}) // 多字段
db.Model(&user).Updates(map[string]interface{}{"name": "New", "age": 25})
03.UpdateColumn
a.跳过钩子
db.Model(&user).UpdateColumn("name", "New") // 跳过钩子和时间戳
04.批量更新
a.条件更新
db.Model(&User{}).Where("age > ?", 18).Updates(map[string]interface{}{"status": "active"})
3.4 删除记录
01.Delete
a.软删除
db.Delete(&user) // 软删除(设置DeletedAt)
db.Delete(&user, 10) // 根据主键删除
02.批量删除
a.条件删除
db.Where("age < ?", 18).Delete(&User{})
db.Delete(&User{}, []int{1, 2, 3}) // 批量删除
03.Unscoped
a.永久删除
db.Unscoped().Delete(&user) // 物理删除
db.Unscoped().Where("age < ?", 18).Delete(&User{})
04.软删除
a.查询过滤
db.Find(&users) // 自动过滤已删除记录
db.Unscoped().Find(&users) // 包含已删除记录
3.5 批量操作
01.批量插入
a.分批插入
db.CreateInBatches(users, 100) // 每批100条
02.批量更新
a.条件更新
db.Model(&User{}).Where("status = ?", "pending").Updates(map[string]interface{}{
"status": "active",
"updated_at": time.Now(),
})
03.批量删除
a.条件删除
db.Where("created_at < ?", time.Now().AddDate(0, -6, 0)).Delete(&User{})
04.性能优化
a.事务批量
db.Transaction(func(tx *gorm.DB) error {
for _, user := range users {
if err := tx.Create(&user).Error; err != nil {
return err
}
}
return nil
})
3.6 原生SQL
01.Raw SQL
a.原生查询
var users []User
db.Raw("SELECT * FROM users WHERE age > ?", 18).Scan(&users)
02.Exec
a.执行SQL
db.Exec("UPDATE users SET status = ? WHERE age > ?", "active", 18)
db.Exec("DELETE FROM users WHERE created_at < ?", time.Now().AddDate(-1, 0, 0))
03.Scan
a.结果映射
type Result struct {
Name string
Count int
}
var results []Result
db.Raw("SELECT name, COUNT(*) as count FROM users GROUP BY name").Scan(&results)
04.使用场景
a.复杂查询
db.Raw(`
SELECT u.*, COUNT(o.id) as order_count
FROM users u
LEFT JOIN orders o ON u.id = o.user_id
GROUP BY u.id
HAVING order_count > 5
`).Scan(&users)
4 查询进阶
4.1 条件查询
01.Where条件
a.参数绑定
db.Where("name = ?", "Alice").Find(&users)
db.Where("age > ?", 18).Find(&users)
db.Where("name IN ?", []string{"Alice", "Bob"}).Find(&users)
02.多条件
a.链式调用
db.Where("name = ?", "Alice").Where("age > ?", 18).Find(&users)
db.Where("name = ? AND age > ?", "Alice", 18).Find(&users)
03.Struct/Map条件
a.结构体条件
db.Where(&User{Name: "Alice", Age: 25}).Find(&users)
db.Where(map[string]interface{}{"name": "Alice", "age": 25}).Find(&users)
04.Not/Or条件
a.逻辑运算
db.Not("name = ?", "Alice").Find(&users)
db.Or("name = ?", "Bob").Or("age > ?", 30).Find(&users)
db.Where("name = ?", "Alice").Or("age > ?", 30).Find(&users)
4.2 排序分页
01.Order排序
a.排序方式
db.Order("age desc").Find(&users)
db.Order("age desc, name").Find(&users)
db.Order(clause.OrderByColumn{Column: clause.Column{Name: "age"}, Desc: true}).Find(&users)
02.Limit/Offset
a.分页查询
db.Limit(10).Offset(20).Find(&users) // 第3页,每页10条
page := 3
pageSize := 10
db.Limit(pageSize).Offset((page - 1) * pageSize).Find(&users)
03.游标分页
a.基于ID分页
var lastID uint = 0
db.Where("id > ?", lastID).Order("id").Limit(10).Find(&users)
// 下一页
lastID = users[len(users)-1].ID
db.Where("id > ?", lastID).Order("id").Limit(10).Find(&users)
04.Scopes
a.可复用分页
func Paginate(page, pageSize int) func(db *gorm.DB) *gorm.DB {
return func(db *gorm.DB) *gorm.DB {
return db.Offset((page - 1) * pageSize).Limit(pageSize)
}
}
db.Scopes(Paginate(2, 10)).Find(&users)
4.3 预加载
01.Preload
a.关联加载
db.Preload("Orders").Find(&users) // 预加载订单
db.Preload("Orders").Preload("Profile").Find(&users) // 多个关联
02.嵌套预加载
a.多层关联
db.Preload("Orders.Items").Find(&users)
db.Preload("Orders.Items.Product").Find(&users)
03.条件预加载
a.过滤关联
db.Preload("Orders", "state = ?", "paid").Find(&users)
db.Preload("Orders", func(db *gorm.DB) *gorm.DB {
return db.Where("amount > ?", 100).Order("created_at desc")
}).Find(&users)
04.Joins预加载
a.JOIN查询
db.Joins("Company").Find(&users)
db.Joins("LEFT JOIN companies ON users.company_id = companies.id").Find(&users)
4.4 子查询
01.Where子查询
a.子查询条件
subQuery := db.Model(&Order{}).Select("AVG(amount)")
db.Where("amount > (?)", subQuery).Find(&orders)
02.From子查询
a.派生表
subQuery := db.Model(&User{}).Select("id, name").Where("age > ?", 18)
db.Table("(?) as u", subQuery).Find(&results)
03.Update子查询
a.子查询更新
db.Model(&User{}).Where("id IN (?)",
db.Model(&Order{}).Select("user_id").Where("amount > ?", 1000),
).Update("vip", true)
04.性能考虑
a.优化建议
// 使用JOIN替代子查询(性能更好)
db.Joins("JOIN orders ON users.id = orders.user_id").
Where("orders.amount > ?", 1000).Find(&users)
4.5 聚合函数
01.Count
a.计数查询
var count int64
db.Model(&User{}).Count(&count)
db.Model(&User{}).Where("age > ?", 18).Count(&count)
02.Sum/Avg
a.聚合计算
var total float64
db.Model(&Order{}).Select("SUM(amount)").Row().Scan(&total)
db.Model(&Order{}).Select("AVG(amount)").Row().Scan(&total)
03.Group/Having
a.分组聚合
type Result struct {
Name string
Count int
}
var results []Result
db.Model(&User{}).Select("name, count(*) as count").
Group("name").Having("count > ?", 1).Scan(&results)
04.Distinct
a.去重查询
db.Distinct("name").Find(&users)
var names []string
db.Model(&User{}).Distinct("name").Pluck("name", &names)
4.6 查询优化
01.索引使用
a.索引优化
// 确保查询条件有索引
db.Where("email = ?", "[email protected] ").Find(&user) // email需要索引
// 复合索引
db.Where("name = ? AND age > ?", "Alice", 18).Find(&users) // (name, age)复合索引
02.查询缓存
a.Redis缓存
key := "users:all"
if cached, err := redis.Get(key); err == nil {
json.Unmarshal(cached, &users)
} else {
db.Find(&users)
data, _ := json.Marshal(users)
redis.Set(key, data, 5*time.Minute)
}
03.批量查询
a.分批处理
db.FindInBatches(&users, 100, func(tx *gorm.DB, batch int) error {
for _, user := range users {
// 处理每批数据
}
return nil
})
04.性能分析
a.慢查询分析
db = db.Debug() // 打印SQL
// 分析执行计划
db.Raw("EXPLAIN SELECT * FROM users WHERE age > ?", 18).Scan(&result)
5 关联关系
5.1 一对一
01.Belongs To
a.多对一关联
type User struct {
ID uint
CompanyID uint
Company Company
}
type Company struct {
ID uint
Name string
}
db.Preload("Company").Find(&users)
02.Has One
a.一对一关联
type User struct {
ID uint
Profile Profile
}
type Profile struct {
ID uint
UserID uint
Bio string
}
db.Preload("Profile").Find(&users)
03.关联操作
a.Association方法
db.Model(&user).Association("Profile").Find(&profile)
db.Model(&user).Association("Profile").Append(&profile)
db.Model(&user).Association("Profile").Replace(&newProfile)
db.Model(&user).Association("Profile").Delete(&profile)
04.自引用
a.树形结构
type Category struct {
ID uint
ParentID *uint
Parent *Category
Children []Category `gorm:"foreignKey:ParentID"`
}
5.2 一对多
01.Has Many
a.一对多关联
type User struct {
ID uint
Orders []Order
}
type Order struct {
ID uint
UserID uint
}
db.Preload("Orders").Find(&users)
02.关联查询
a.条件预加载
db.Preload("Orders", "status = ?", "paid").Find(&users)
db.Preload("Orders", func(db *gorm.DB) *gorm.DB {
return db.Order("created_at desc").Limit(5)
}).Find(&users)
03.关联创建
a.级联创建
user := User{
Name: "Alice",
Orders: []Order{
{Amount: 100},
{Amount: 200},
},
}
db.Create(&user) // 自动创建关联订单
04.级联操作
a.级联删除
db.Select("Orders").Delete(&user) // 同时删除关联订单
5.3 多对多
01.Many To Many
a.多对多关联
type User struct {
ID uint
Roles []Role `gorm:"many2many:user_roles;"`
}
type Role struct {
ID uint
Name string
}
db.Preload("Roles").Find(&users)
02.中间表字段
a.自定义中间表
type UserRole struct {
UserID uint
RoleID uint
CreatedAt time.Time
}
type User struct {
Roles []Role `gorm:"many2many:user_roles;"`
}
03.关联操作
a.多对多操作
db.Model(&user).Association("Roles").Append(&roles)
db.Model(&user).Association("Roles").Replace(&newRoles)
db.Model(&user).Association("Roles").Delete(&role)
db.Model(&user).Association("Roles").Clear()
04.自定义中间表
a.完整定义
type User struct {
Roles []Role `gorm:"many2many:user_roles;joinForeignKey:UserID;joinReferences:RoleID"`
}
5.4 关联查询
01.预加载策略
a.Preload vs Joins
// Preload: 两次查询,适合一对多
db.Preload("Orders").Find(&users)
// SQL: SELECT * FROM users; SELECT * FROM orders WHERE user_id IN (...)
// Joins: 一次查询,适合一对一
db.Joins("Company").Find(&users)
// SQL: SELECT users.*, companies.* FROM users LEFT JOIN companies ON ...
02.条件预加载
a.过滤和排序
db.Preload("Orders", "status = ?", "paid").Find(&users)
db.Preload("Orders", func(db *gorm.DB) *gorm.DB {
return db.Where("amount > ?", 100).Order("created_at desc").Limit(5)
}).Find(&users)
03.嵌套预加载
a.多层关联
db.Preload("Orders.Items").Find(&users)
db.Preload("Orders.Items.Product").Find(&users)
db.Preload("Orders", "status = ?", "paid").
Preload("Orders.Items").Find(&users)
04.关联计数
a.统计关联
type Result struct {
UserID uint
OrderCount int64
}
db.Model(&User{}).
Select("users.id as user_id, count(orders.id) as order_count").
Joins("left join orders on orders.user_id = users.id").
Group("users.id").Scan(&results)
5.5 关联更新
01.Association模式
a.关联操作
// 添加关联
db.Model(&user).Association("Roles").Append(&role)
db.Model(&user).Association("Roles").Append(&[]Role{role1, role2})
// 替换关联
db.Model(&user).Association("Roles").Replace(&newRoles)
// 删除关联
db.Model(&user).Association("Roles").Delete(&role)
// 清空关联
db.Model(&user).Association("Roles").Clear()
02.Save级联
a.级联保存
user := User{
Name: "Alice",
Profile: Profile{Bio: "Developer"},
Orders: []Order{
{Amount: 100},
{Amount: 200},
},
}
db.Save(&user) // 自动创建/更新关联
03.Select Omit
a.控制级联
// 只保存指定关联
db.Select("Name", "Orders").Save(&user)
// 排除关联
db.Omit("Orders").Save(&user)
// 排除所有关联
db.Omit(clause.Associations).Save(&user)
04.事务处理
a.关联事务
db.Transaction(func(tx *gorm.DB) error {
if err := tx.Create(&user).Error; err != nil {
return err
}
if err := tx.Model(&user).Association("Orders").Append(&orders).Error; err != nil {
return err
}
return nil
})
5.6 多态关联
01.多态定义
a.多态模型
type Comment struct {
ID uint
Body string
CommentableID uint
CommentableType string
}
type Post struct {
ID uint
Comments []Comment `gorm:"polymorphic:Commentable;"`
}
type Video struct {
ID uint
Comments []Comment `gorm:"polymorphic:Commentable;"`
}
02.多态查询
a.预加载多态
db.Preload("Comments").Find(&posts)
db.Preload("Comments").Find(&videos)
// 条件过滤
db.Preload("Comments", "body LIKE ?", "%good%").Find(&posts)
03.多态创建
a.创建多态关联
post := Post{
Title: "Hello",
Comments: []Comment{
{Body: "Great post!"},
{Body: "Thanks!"},
},
}
db.Create(&post)
// CommentableType 自动设置为 "Post"
// CommentableID 自动设置为 post.ID
04.使用场景
a.评论系统
// 文章评论
type Article struct {
ID uint
Comments []Comment `gorm:"polymorphic:Commentable;"`
}
// 视频评论
type Video struct {
ID uint
Comments []Comment `gorm:"polymorphic:Commentable;"`
}
// 查询所有评论
db.Where("commentable_type = ? AND commentable_id = ?", "Article", articleID).
Find(&comments)
6 事务与迁移
6.1 事务处理
01.手动事务
a.手动控制
tx := db.Begin()
if err := tx.Create(&user).Error; err != nil {
tx.Rollback()
return err
}
if err := tx.Create(&order).Error; err != nil {
tx.Rollback()
return err
}
tx.Commit()
02.事务回调
a.自动事务
db.Transaction(func(tx *gorm.DB) error {
if err := tx.Create(&user).Error; err != nil {
return err // 自动回滚
}
if err := tx.Create(&order).Error; err != nil {
return err
}
return nil // 自动提交
})
03.嵌套事务
a.SavePoint
db.Transaction(func(tx *gorm.DB) error {
tx.Create(&user)
tx.SavePoint("sp1")
tx.Create(&order)
tx.RollbackTo("sp1") // 回滚到保存点
return nil
})
04.事务隔离
a.隔离级别
db.Exec("SET TRANSACTION ISOLATION LEVEL READ COMMITTED")
6.2 自动迁移
01.AutoMigrate
a.自动迁移
db.AutoMigrate(&User{}, &Order{}, &Product{})
// 自动创建表、添加缺失字段、创建索引
02.迁移限制
a.注意事项
// AutoMigrate 只会:
// 1. 创建不存在的表
// 2. 添加缺失的字段
// 3. 创建缺失的索引
// 不会:删除字段、修改字段类型、删除索引
03.迁移选项
a.自定义选项
db.Set("gorm:table_options", "ENGINE=InnoDB").AutoMigrate(&User{})
04.注意事项
a.生产环境
// 生产环境建议:
// 1. 使用迁移工具而非AutoMigrate
// 2. 先在测试环境验证
// 3. 做好数据备份
6.3 手动迁移
01.Migrator接口
a.表操作
m := db.Migrator()
m.CreateTable(&User{})
m.DropTable(&User{})
m.HasTable(&User{})
m.RenameTable(&User{}, &UserBackup{})
02.字段管理
a.字段操作
m.AddColumn(&User{}, "Age")
m.DropColumn(&User{}, "Age")
m.AlterColumn(&User{}, "Name")
m.HasColumn(&User{}, "Name")
m.RenameColumn(&User{}, "Name", "FullName")
03.索引管理
a.索引操作
m.CreateIndex(&User{}, "Email")
m.DropIndex(&User{}, "idx_users_email")
m.HasIndex(&User{}, "idx_users_email")
04.约束管理
a.约束操作
m.CreateConstraint(&User{}, "Orders")
m.DropConstraint(&User{}, "fk_users_company")
6.4 数据填充
01.Seed数据
a.初始数据
func SeedUsers(db *gorm.DB) error {
users := []User{
{Name: "Admin", Email: "[email protected] ", Role: "admin"},
{Name: "User1", Email: "[email protected] ", Role: "user"},
{Name: "User2", Email: "[email protected] ", Role: "user"},
}
return db.Create(&users).Error
}
// 在main中调用
if err := SeedUsers(db); err != nil {
log.Fatal(err)
}
02.批量插入
a.性能优化
// 分批插入,避免内存溢出
users := make([]User, 10000)
// ... 填充数据
db.CreateInBatches(users, 100) // 每批100条
// 使用事务提升性能
db.Transaction(func(tx *gorm.DB) error {
return tx.CreateInBatches(users, 100).Error
})
03.数据导入
a.CSV导入
import "encoding/csv"
func ImportFromCSV(db *gorm.DB, filename string) error {
file, _ := os.Open(filename)
defer file.Close()
reader := csv.NewReader(file)
records, _ := reader.ReadAll()
var users []User
for _, record := range records[1:] { // 跳过表头
users = append(users, User{
Name: record[0],
Email: record[1],
})
}
return db.CreateInBatches(users, 100).Error
}
b.JSON导入
import "encoding/json"
func ImportFromJSON(db *gorm.DB, filename string) error {
data, _ := os.ReadFile(filename)
var users []User
json.Unmarshal(data, &users)
return db.CreateInBatches(users, 100).Error
}
04.数据验证
a.验证规则
func ValidateUser(user *User) error {
// 唯一性验证
var count int64
db.Model(&User{}).Where("email = ?", user.Email).Count(&count)
if count > 0 {
return errors.New("邮箱已存在")
}
// 完整性验证
if user.Name == "" || user.Email == "" {
return errors.New("必填字段不能为空")
}
// 业务规则验证
if user.Age < 0 || user.Age > 150 {
return errors.New("年龄不合法")
}
return nil
}
6.5 版本管理
01.迁移工具
a.golang-migrate
// 安装
go install -tags 'mysql' github.com/golang-migrate/migrate/v4/cmd/migrate@latest
// 创建迁移文件
migrate create -ext sql -dir migrations -seq create_users_table
// 执行迁移
migrate -path migrations -database "mysql://user:pass@tcp(localhost:3306)/db" up
// 回滚
migrate -path migrations -database "mysql://..." down 1
b.goose
// 安装
go install github.com/pressly/goose/v3/cmd/goose@latest
// 创建迁移
goose -dir migrations create add_users_table sql
// 执行迁移
goose -dir migrations mysql "user:pass@/dbname" up
// 回滚
goose -dir migrations mysql "user:pass@/dbname" down
02.版本控制
a.迁移文件示例
// 000001_create_users_table.up.sql
CREATE TABLE users (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(100) NOT NULL,
email VARCHAR(100) NOT NULL UNIQUE,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
// 000001_create_users_table.down.sql
DROP TABLE IF EXISTS users;
b.版本查询
// 查看当前版本
migrate -path migrations -database "..." version
// 查看迁移状态
goose -dir migrations mysql "..." status
03.团队协作
a.迁移文件管理
migrations/
├── 000001_create_users_table.up.sql
├── 000001_create_users_table.down.sql
├── 000002_add_users_age.up.sql
├── 000002_add_users_age.down.sql
└── README.md
// 命名规范:{version}_{description}.{up|down}.sql
// 版本号递增,避免冲突
b.冲突解决
// 1. 团队成员各自创建迁移文件
// 2. 合并时检查版本号冲突
// 3. 重新编号冲突的迁移文件
// 4. 更新迁移历史记录
// 最佳实践:
// - 使用时间戳作为版本号
// - 提交前先拉取最新代码
// - 迁移文件一旦合并不要修改
04.生产部署
a.部署流程
// 1. 备份数据库
mysqldump -u user -p dbname > backup_$(date +%Y%m%d_%H%M%S).sql
// 2. 在测试环境验证
migrate -path migrations -database "test_db_url" up
// 3. 生产环境执行
migrate -path migrations -database "prod_db_url" up
// 4. 验证迁移结果
migrate -path migrations -database "prod_db_url" version
// 5. 如有问题立即回滚
migrate -path migrations -database "prod_db_url" down 1
b.灰度发布
// 1. 先迁移数据库(向后兼容)
// 2. 灰度发布新代码(小流量)
// 3. 监控错误和性能
// 4. 逐步扩大流量
// 5. 全量发布
// 回滚策略:
// - 代码回滚:回滚到上一版本
// - 数据库回滚:执行down迁移
// - 数据恢复:从备份恢复
7 高级特性
7.1 插件系统
01.插件接口
a.自定义插件
type MyPlugin struct{}
func (p *MyPlugin) Name() string {
return "my_plugin"
}
func (p *MyPlugin) Initialize(db *gorm.DB) error {
// 初始化逻辑
return nil
}
db.Use(&MyPlugin{})
02.回调系统
a.注册回调
db.Callback().Create().Before("gorm:create").Register("my_plugin:before_create",
func(db *gorm.DB) {
// 创建前回调
})
03.自定义插件
a.日志插件
type LogPlugin struct{}
func (p *LogPlugin) Initialize(db *gorm.DB) error {
db.Callback().Query().After("gorm:query").Register("log:after_query",
func(db *gorm.DB) {
log.Printf("SQL: %v", db.Statement.SQL.String())
})
return nil
}
04.插件注册
a.使用插件
db.Use(&LogPlugin{})
db.Use(&CachePlugin{})
7.2 性能优化
01.连接池优化
a.连接池配置
sqlDB, _ := db.DB()
sqlDB.SetMaxIdleConns(10)
sqlDB.SetMaxOpenConns(100)
sqlDB.SetConnMaxLifetime(time.Hour)
02.查询优化
a.索引优化
// 确保查询字段有索引
db.Where("email = ?", email).Find(&user) // email需要索引
// 使用复合索引
db.Where("name = ? AND age > ?", name, age).Find(&users)
03.预加载优化
a.Joins vs Preload
// Preload: 两次查询
db.Preload("Orders").Find(&users)
// Joins: 一次查询(LEFT JOIN)
db.Joins("Orders").Find(&users)
04.批量操作
a.批量处理
db.CreateInBatches(users, 100) // 分批插入
db.FindInBatches(&users, 100, func(tx *gorm.DB, batch int) error {
// 分批处理
return nil
})
7.3 连接池
01.连接池配置
a.参数设置
sqlDB, _ := db.DB()
sqlDB.SetMaxIdleConns(10) // 最大空闲连接
sqlDB.SetMaxOpenConns(100) // 最大打开连接
sqlDB.SetConnMaxLifetime(time.Hour) // 连接最大生命周期
02.连接监控
a.Stats监控
stats := sqlDB.Stats()
fmt.Printf("Open: %d, InUse: %d, Idle: %d\n",
stats.OpenConnections, stats.InUse, stats.Idle)
03.连接泄漏
a.检测泄漏
// 定期检查连接数
ticker := time.NewTicker(1 * time.Minute)
go func() {
for range ticker.C {
stats := sqlDB.Stats()
if stats.OpenConnections > 80 {
log.Warn("连接数过高")
}
}
}()
04.性能调优
a.最佳实践
// 根据并发量调整
// MaxOpenConns = (核心数 * 2) + 磁盘数
// MaxIdleConns = MaxOpenConns / 2
7.4 读写分离
01.主从配置
a.DBResolver
import "gorm.io/plugin/dbresolver"
db.Use(dbresolver.Register(dbresolver.Config{
Sources: []gorm.Dialector{mysql.Open(writeDSN)},
Replicas: []gorm.Dialector{mysql.Open(readDSN1), mysql.Open(readDSN2)},
}))
02.读写策略
a.自动路由
db.Create(&user) // 写主库
db.Find(&users) // 读从库
db.Clauses(dbresolver.Write).Find(&users) // 强制读主库
03.从库配置
a.负载均衡
db.Use(dbresolver.Register(dbresolver.Config{
Replicas: []gorm.Dialector{
mysql.Open(readDSN1),
mysql.Open(readDSN2),
},
Policy: dbresolver.RandomPolicy{}, // 随机策略
}))
04.使用场景
a.高并发读
// 适用于读多写少的场景
// 查询走从库,写入走主库
7.5 分库分表
01.水平分表
a.分表策略
// 按用户ID分表
tableName := fmt.Sprintf("users_%d", userID % 10)
db.Table(tableName).Create(&user)
02.垂直分库
a.业务分库
userDB := gorm.Open(mysql.Open(userDSN))
orderDB := gorm.Open(mysql.Open(orderDSN))
03.Sharding插件
a.使用Sharding
import "gorm.io/sharding"
db.Use(sharding.Register(sharding.Config{
ShardingKey: "user_id",
NumberOfShards: 10,
}))
04.注意事项
a.跨库查询
// 避免跨库JOIN
// 使用应用层聚合
7.6 最佳实践
01.模型设计
a.字段规范
type User struct {
ID uint `gorm:"primaryKey"`
Name string `gorm:"size:100;not null;index"`
Email string `gorm:"size:100;uniqueIndex;not null"`
CreatedAt time.Time
UpdatedAt time.Time
}
02.查询优化
a.优化建议
// 1. 使用索引
// 2. 避免SELECT *
// 3. 使用预加载解决N+1
// 4. 批量操作
db.Select("id", "name").Find(&users)
03.事务使用
a.事务范围
// 事务范围尽可能小
db.Transaction(func(tx *gorm.DB) error {
// 只包含必要的操作
return nil
})
04.错误处理
a.统一处理
if err := db.Create(&user).Error; err != nil {
log.Error("创建用户失败", err)
return err
}