GORM — 全功能 ORM
GORM 是 Go 最流行的 ORM 库,功能完整,支持 MySQL、PostgreSQL、SQLite、SQL Server。
安装
bash
go get -u gorm.io/gorm
go get -u gorm.io/driver/postgres # 或 mysql / sqlite连接数据库
go
import (
"gorm.io/driver/postgres"
"gorm.io/gorm"
"gorm.io/gorm/logger"
)
func NewDB(dsn string) (*gorm.DB, error) {
db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{
Logger: logger.Default.LogMode(logger.Info),
NamingStrategy: schema.NamingStrategy{
TablePrefix: "app_", // 表名前缀
SingularTable: false, // 使用复数表名
},
PrepareStmt: true, // 缓存预编译语句,提升性能
})
if err != nil {
return nil, err
}
// 配置连接池
sqlDB, _ := db.DB()
sqlDB.SetMaxIdleConns(10)
sqlDB.SetMaxOpenConns(100)
sqlDB.SetConnMaxLifetime(time.Hour)
return db, nil
}模型定义
go
import "gorm.io/gorm"
// gorm.Model 包含 ID, CreatedAt, UpdatedAt, DeletedAt
type User struct {
gorm.Model
Name string `gorm:"size:100;not null"`
Email string `gorm:"uniqueIndex;size:200;not null"`
Age int `gorm:"check:age >= 0"`
Role string `gorm:"default:user;size:20"`
Active bool `gorm:"default:true"`
// 关联
Profile Profile `gorm:"foreignKey:UserID"`
Orders []Order `gorm:"foreignKey:UserID"`
}
type Profile struct {
ID uint `gorm:"primaryKey"`
UserID uint `gorm:"uniqueIndex"`
Bio string `gorm:"type:text"`
Avatar string `gorm:"size:500"`
}
type Order struct {
gorm.Model
UserID uint `gorm:"index;not null"`
Amount float64 `gorm:"type:decimal(10,2)"`
Status string `gorm:"size:20;default:pending"`
Items []OrderItem `gorm:"foreignKey:OrderID"`
}
// 自动迁移
db.AutoMigrate(&User{}, &Profile{}, &Order{})CRUD 操作
创建
go
// 创建单条记录
user := User{Name: "Alice", Email: "alice@example.com", Age: 30}
result := db.Create(&user)
fmt.Println(user.ID) // 自动填充 ID
fmt.Println(result.Error) // 错误
fmt.Println(result.RowsAffected)
// 批量创建
users := []User{
{Name: "Bob", Email: "bob@example.com"},
{Name: "Charlie", Email: "charlie@example.com"},
}
db.CreateInBatches(users, 100) // 每批 100 条
// 指定字段创建
db.Select("Name", "Email").Create(&user)
// 忽略某些字段
db.Omit("Age", "Role").Create(&user)查询
go
// 查询单条
var user User
db.First(&user, 1) // 按主键
db.First(&user, "email = ?", "alice@example.com")
db.Where("name = ?", "Alice").First(&user)
// 查询多条
var users []User
db.Find(&users) // 全部
db.Where("age > ?", 18).Find(&users)
db.Where("role IN ?", []string{"admin", "mod"}).Find(&users)
// 链式查询
db.Where("active = ?", true).
Where("age BETWEEN ? AND ?", 18, 60).
Order("created_at DESC").
Limit(10).
Offset(20).
Find(&users)
// 选择字段
db.Select("id", "name", "email").Find(&users)
// 扫描到自定义结构
type UserSummary struct {
ID uint
Name string
Email string
}
var summaries []UserSummary
db.Model(&User{}).Select("id, name, email").Scan(&summaries)
// 计数
var count int64
db.Model(&User{}).Where("active = ?", true).Count(&count)
// 分页
func Paginate(page, pageSize int) func(db *gorm.DB) *gorm.DB {
return func(db *gorm.DB) *gorm.DB {
offset := (page - 1) * pageSize
return db.Offset(offset).Limit(pageSize)
}
}
db.Scopes(Paginate(2, 10)).Find(&users)更新
go
// 更新单个字段
db.Model(&user).Update("name", "Alice Updated")
// 更新多个字段(struct 只更新非零值字段)
db.Model(&user).Updates(User{Name: "Alice", Age: 31})
// 更新多个字段(map 更新所有指定字段,包括零值)
db.Model(&user).Updates(map[string]interface{}{
"name": "Alice",
"age": 0, // 会更新为 0
"active": false,
})
// 条件更新
db.Model(&User{}).
Where("active = ?", false).
Update("deleted_at", time.Now())
// 使用表达式
db.Model(&user).Update("age", gorm.Expr("age + ?", 1))删除
go
// 软删除(模型有 DeletedAt 字段时)
db.Delete(&user, 1)
db.Delete(&User{}, "age < ?", 18)
// 查询时默认过滤软删除记录
db.Find(&users) // 不包含已删除
// 包含软删除记录
db.Unscoped().Find(&users)
// 硬删除
db.Unscoped().Delete(&user)关联操作
go
// 预加载(避免 N+1 问题)
var users []User
db.Preload("Profile").Find(&users)
db.Preload("Orders").Preload("Orders.Items").Find(&users)
// 条件预加载
db.Preload("Orders", "status = ?", "completed").Find(&users)
// 嵌套预加载
db.Preload("Orders.Items.Product").Find(&users)
// 创建关联
user := User{
Name: "Alice",
Profile: Profile{Bio: "Go developer"},
Orders: []Order{
{Amount: 99.99, Status: "pending"},
},
}
db.Create(&user)
// 添加关联
db.Model(&user).Association("Orders").Append(&Order{Amount: 50})
// 查询关联
var orders []Order
db.Model(&user).Association("Orders").Find(&orders)
// 统计关联数量
count := db.Model(&user).Association("Orders").Count()事务
go
// 自动事务
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 // 自动提交
})
// 手动事务
tx := db.Begin()
defer func() {
if r := recover(); r != nil {
tx.Rollback()
}
}()
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()
// 嵌套事务(使用 SavePoint)
db.Transaction(func(tx *gorm.DB) error {
tx.Create(&user)
tx.Transaction(func(tx2 *gorm.DB) error {
tx2.Create(&order)
return errors.New("回滚内层事务") // 只回滚内层
})
return nil // 外层提交
})Hooks(钩子)
go
type User struct {
gorm.Model
Password string `gorm:"-"` // 不存储原始密码
PassHash string
}
// 创建前加密密码
func (u *User) BeforeCreate(tx *gorm.DB) error {
hash, err := bcrypt.GenerateFromPassword([]byte(u.Password), 12)
if err != nil {
return err
}
u.PassHash = string(hash)
return nil
}
// 更新前验证
func (u *User) BeforeUpdate(tx *gorm.DB) error {
if u.Age < 0 {
return errors.New("年龄不能为负数")
}
return nil
}
// 可用的 Hooks:
// BeforeCreate, AfterCreate
// BeforeUpdate, AfterUpdate
// BeforeDelete, AfterDelete
// BeforeFind, AfterFind原生 SQL
go
// 原生查询
var users []User
db.Raw("SELECT * FROM users WHERE age > ? AND active = ?", 18, true).Scan(&users)
// 原生执行
db.Exec("UPDATE users SET active = ? WHERE last_login < ?", false, cutoff)
// 命名参数
db.Raw("SELECT * FROM users WHERE name = @name AND age = @age",
sql.Named("name", "Alice"),
sql.Named("age", 30),
).Scan(&users)性能建议
- 使用
Select只查询需要的字段 - 批量操作用
CreateInBatches - 开启
PrepareStmt: true缓存预编译语句 - 避免在循环中查询(N+1 问题),用
Preload或Joins - 生产环境关闭 SQL 日志或设置为 Warn 级别