GORM - Go ORM 数据库操作
GORM 是 Go 最流行的 ORM 库,支持多种数据库,提供模型定义、CRUD 操作、关联查询、事务处理等功能。掌握 GORM 是开发 Go 数据库应用的基础。
📌 核心概念
📊
模型定义
结构体映射表
type Model
🔍
CRUD
增删改查
Create/Find
🔗
关联
BelongsTo/HasMany
gorm:"foreignKey"
💾
事务
原子操作
Transaction
快速开始
📝 连接数据库
package main
import (
"gorm.io/driver/mysql"
"gorm.io/gorm"
"log"
)
func main() {
// MySQL 连接
dsn := "user:pass@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.Panic("Failed to connect database")
}
// 获取底层 SQL DB
sqlDB, _ := db.DB()
sqlDB.SetMaxIdleConns(10)
sqlDB.SetMaxOpenConns(100)
// PostgreSQL
// dsn := "host=localhost user=postgres password=xxx dbname=db port=5432"
// db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{})
// SQLite
// db, err := gorm.Open(sqlite.Open("test.db"), &gorm.Config{})
}
模型定义
📝 定义模型和迁移
package main
import (
"time"
"gorm.io/gorm"
)
// 基础模型 (ID, CreatedAt, UpdatedAt, DeletedAt)
type User struct {
gorm.Model
Name string `gorm:"size:100;not null"`
Email string `gorm:"size:255;uniqueIndex"`
Age int `gorm:"comment:'用户年龄'"`
Birthday *time.Time
Active bool `gorm:"default:true"`
}
// 自定义表名
func (User) TableName() string {
return "tb_user"
}
// 自动迁移
func migrate(db *gorm.DB) {
db.AutoMigrate(&User{})
}
💡 GORM Tag 说明
- gorm:"primaryKey": 主键
- gorm:"autoIncrement": 自增
- gorm:"size:255": 字段大小
- gorm:"uniqueIndex": 唯一索引
- gorm:"default:value": 默认值
- gorm:"not null": 非空
- gorm:"comment:'文本'": 字段注释
CRUD 操作
创建数据
📝 Create 操作
// 创建单条记录
user := User{Name: "Alice", Email: "alice@example.com"}
db.Create(&user)
fmt.Println(user.ID) // 自动填充 ID
// 批量创建
users := []User{
{Name: "Bob", Email: "bob@example.com"},
{Name: "Carol", Email: "carol@example.com"},
}
db.Create(&users)
// 选择字段创建
db.Select("Name", "Email").Create(&user)
// 忽略字段创建
db.Omit("Age").Create(&user)
查询数据
📝 Find/First 查询
var user User
var users []User
// 查找第一条
db.First(&user) // SELECT * FROM users ORDER BY id LIMIT 1
db.First(&user, 10) // SELECT * FROM users WHERE id = 10
db.First(&user, "name = ?", "Alice")
// 查找所有
db.Find(&users) // SELECT * FROM users
// 条件查询
db.Where("age > ?", 18).Find(&users)
db.Where("name = ? AND age > ?", "Alice", 18).Find(&users)
db.Where(map[string]interface{}{"name": "Alice"}).Find(&users)
// IN 查询
db.Where("name IN ?", []string{"Alice", "Bob"}).Find(&users)
// 范围查询
db.Where("age BETWEEN ? AND ?", 18, 30).Find(&users)
// Like 查询
db.Where("name LIKE ?", "%li%").Find(&users)
// 选择字段
db.Select("name, email").Find(&users)
// 排序
db.Order("age DESC").Find(&users)
db.Order("age DESC, name ASC").Find(&users)
// 限制和偏移
db.Limit(3).Offset(10).Find(&users)
// 计数
var total int64
db.Model(&User{}).Count(&total)
// 聚合
var avgAge float64
db.Model(&User{}).Select("AVG(age)").Scan(&avgAge)
更新数据
📝 Update 操作
// 更新单字段
db.Model(&User{}).Where("id = ?", 1).Update("name", "New Name")
// 更新多字段
db.Model(&User{}).Where("id = ?", 1).Updates(map[string]interface{}{
"name": "New Name",
"age": 25,
})
// 使用结构体更新
db.Model(&User{}).Where("id = ?", 1).Updates(User{
Name: "New Name",
})
// 只更新非零值
db.Model(&User{}).Select([]string{"Name", "Age"}).Updates(User{
Name: "New Name",
Age: 0, // 会被更新为 0
})
删除数据
📝 Delete 操作
// 软删除 (需要模型有 DeletedAt 字段)
db.Delete(&user) // WHERE deleted_at IS NULL
// 硬删除
db.Unscoped().Delete(&user)
// 条件删除
db.Where("age < ?", 18).Delete(&User{})
// 批量删除
db.Delete(&[]User{}, []int64{1, 2, 3})
关联查询
📝 定义和使用关联
type User struct {
gorm.Model
Name string
Orders []Order `gorm:"foreignKey:UserID"`
Profile *Profile `gorm:"foreignKey:UserID"`
}
type Order struct {
gorm.Model
UserID uint
Amount float64
User *User `gorm:"foreignKey:UserID"`
}
type Profile struct {
gorm.Model
UserID uint
Bio string
User *User `gorm:"foreignKey:UserID"`
}
// 预加载关联
var user User
db.Preload("Orders").First(&user, 1)
// 预加载多个关联
db.Preload("Orders").Preload("Profile").First(&user)
// 条件预加载
db.Preload("Orders", "amount > ?", 100).First(&user)
// 嵌套预加载
db.Preload("Orders.User").Find(&orders)
事务处理
📝 事务操作
// 基础事务
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()
// 使用 Transaction 方法
err := 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
})
if err != nil {
// 自动回滚
}
最佳实践
✅ GORM 使用建议
- 使用指针: Create/Update/Delete 使用指针
- 检查错误: 始终检查 db.Error
- 使用事务: 多表操作使用事务
- 预加载: 使用 Preload 避免 N+1 查询
- 连接池: 配置 SetMaxIdleConns/SetMaxOpenConns
- 慢查询日志: 配置 Logger 记录慢查询
🚨 常见陷阱
- 共享 DB 实例: DB 实例是并发安全的,可以共享
- 忘记错误检查: db.Find() 后检查 db.Error
- 零值更新: Updates 默认忽略零值
- 软删除查询: Unscoped 才能查询已删除数据
- N+1 查询: 使用 Preload 预加载关联