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 开发者来说是非常重要的。