GORM 超详细总结

GORM 超详细总结

1. GORM 简介

GORM 是 Go 语言的一个 ORM (Object-Relational Mapping) 库,全称为 Go ORM。它提供了友好的 API 来操作数据库,支持多种数据库(MySQL、PostgreSQL、SQLite、SQL Server 等)。

主要特性:

  • 全功能 ORM

  • 关联 (Has One, Has Many, Belongs To, Many To Many, Polymorphism)

  • 钩子 (Before/After Create/Save/Update/Delete/Find)

  • 预加载

  • 事务

  • 复合主键

  • SQL 构建器

  • 自动迁移

  • 日志

  • 可扩展的插件系统

  • 每个特性都有测试覆盖

2. 安装与配置

安装:

go get -u gorm.io/gorm
go get -u gorm.io/driver/mysql  # 或其他数据库驱动

基本配置:

import (
  "gorm.io/gorm"
  "gorm.io/driver/mysql"
)
​
func main() {
  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 {
    panic("failed to connect database")
  }
  
  // 迁移 schema
  db.AutoMigrate(&Product{})
}

3. 模型定义

基本模型:

type User struct {
  gorm.Model
  Name         string
  Email        *string
  Age          uint8
  Birthday     *time.Time
  MemberNumber sql.NullString
  ActivatedAt  sql.NullTime
}

gorm.Model:

type Model struct {
  ID        uint `gorm:"primarykey"`
  CreatedAt time.Time
  UpdatedAt time.Time
  DeletedAt gorm.DeletedAt `gorm:"index"`
}

字段标签:

type User struct {
  Name string `gorm:"type:varchar(100);uniqueIndex"`
  Age  int    `gorm:"default:18"`
}

常用标签:

  • primaryKey - 主键

  • column - 指定列名

  • type - 列数据类型

  • size - 列大小

  • default - 默认值

  • not null - 非空

  • unique - 唯一

  • uniqueIndex - 唯一索引

  • index - 普通索引

  • check - 检查约束

  • <- - 字段权限(create, update)

  • -> - 字段权限(read)

  • - - 忽略字段

4. CRUD 操作

创建记录:

user := User{Name: "Jinzhu", Age: 18}
​
result := db.Create(&user) // 通过数据的指针来创建
​
user.ID             // 返回插入数据的主键
result.Error        // 返回 error
result.RowsAffected // 返回插入记录的条数

批量创建:

var users = []User{{Name: "jinzhu1"}, {Name: "jinzhu2"}, {Name: "jinzhu3"}}
db.Create(&users)

查询记录:

单条查询:

// 获取第一条记录(主键升序)
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;
​
result := db.First(&user)
result.RowsAffected // 返回找到的记录数
result.Error        // returns error or nil

条件查询:

// 获取第一条匹配的记录
db.Where("name = ?", "jinzhu").First(&user)
// SELECT * FROM users WHERE name = 'jinzhu' ORDER BY id LIMIT 1;
​
// 获取所有匹配的记录
db.Where("name <> ?", "jinzhu").Find(&users)
// SELECT * FROM users WHERE name <> 'jinzhu';
​
// IN
db.Where("name IN ?", []string{"jinzhu", "jinzhu 2"}).Find(&users)
// SELECT * FROM users WHERE name IN ('jinzhu','jinzhu 2');
​
// LIKE
db.Where("name LIKE ?", "%jin%").Find(&users)
// SELECT * FROM users WHERE name LIKE '%jin%';
​
// AND
db.Where("name = ? AND age >= ?", "jinzhu", "22").Find(&users)
// SELECT * FROM users WHERE name = 'jinzhu' AND age >= 22;
​
// 主键查询
db.First(&user, 10)
// SELECT * FROM users WHERE id = 10;

更新记录:

// 更新单个字段
db.Model(&user).Update("name", "hello")
// UPDATE users SET name='hello', updated_at='2013-11-17 21:34:10' WHERE id=111;
​
// 更新多个字段
db.Model(&user).Updates(User{Name: "hello", Age: 18})
// UPDATE users SET name='hello', age=18, updated_at='2013-11-17 21:34:10' WHERE id=111;
​
// 使用 map 更新多个字段
db.Model(&user).Updates(map[string]interface{}{"name": "hello", "age": 18})

删除记录:

// 删除一条记录
db.Delete(&user)
// DELETE FROM users WHERE id = 10;
​
// 带条件的删除
db.Where("name = ?", "jinzhu").Delete(&user)
// DELETE FROM users WHERE name = 'jinzhu';
​
// 批量删除
db.Delete(&User{}, "name LIKE ?", "%jinzhu%")
// DELETE FROM users WHERE name LIKE '%jinzhu%';

5. 高级查询

预加载:

type User struct {
  gorm.Model
  Name      string
  Orders    []Order
}
​
type Order struct {
  gorm.Model
  UserID uint
  Price  float64
}
​
// 预加载 Orders
db.Preload("Orders").Find(&users)
// SELECT * FROM users;
// SELECT * FROM orders WHERE user_id IN (1,2,3,4);
​
// 嵌套预加载
db.Preload("Orders.OrderItems").Find(&users)

关联查询:

var user User
db.First(&user)
​
var orders []Order
db.Model(&user).Association("Orders").Find(&orders)

作用域:

func AmountGreaterThan1000(db *gorm.DB) *gorm.DB {
  return db.Where("amount > ?", 1000)
}
​
func PaidWithCreditCard(db *gorm.DB) *gorm.DB {
  return db.Where("pay_mode = ?", "card")
}
​
db.Scopes(AmountGreaterThan1000, PaidWithCreditCard).Find(&orders)
// 查找所有金额大于 1000 且使用信用卡支付的订单

原生 SQL:

db.Raw("SELECT id, name FROM users WHERE name = ?", "jinzhu").Scan(&result)
​
db.Exec("DROP TABLE users")

6. 事务

自动事务:

db.Transaction(func(tx *gorm.DB) error {
  // 在事务中执行一些 db 操作
  if err := tx.Create(&Animal{Name: "Giraffe"}).Error; err != nil {
    // 返回任何错误都会回滚事务
    return err
  }
​
  if err := tx.Create(&Animal{Name: "Lion"}).Error; err != nil {
    return err
  }
​
  // 返回 nil 提交事务
  return nil
})

手动事务:

// 开始事务
tx := db.Begin()
​
// 在事务中执行一些 db 操作
if err := tx.Create(&Animal{Name: "Giraffe"}).Error; err != nil {
  tx.Rollback()
  return
}
​
if err := tx.Create(&Animal{Name: "Lion"}).Error; err != nil {
  tx.Rollback()
  return
}
​
// 提交事务
tx.Commit()

7. 钩子(Hooks)

GORM 提供了以下钩子:

  • BeforeSave

  • BeforeCreate

  • AfterCreate

  • BeforeUpdate

  • AfterUpdate

  • BeforeDelete

  • AfterDelete

  • AfterFind

示例:

func (u *User) BeforeCreate(tx *gorm.DB) (err error) {
  u.UUID = uuid.New()
  return
}

8. 性能优化

禁用默认事务:

db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{
  SkipDefaultTransaction: true,
})

批量插入:

var users = []User{{Name: "jinzhu1"}, {Name: "jinzhu2"}, {Name: "jinzhu3"}}
db.CreateInBatches(users, 100)

查询优化:

// 只查询需要的字段
db.Select("name", "age").Find(&users)
​
// 使用 Pluck 获取单列
var ages []int64
db.Model(&User{}).Pluck("age", &ages)

9. 错误处理

GORM 的错误处理:

if err := db.Where("name = ?", "jinzhu").First(&user).Error; err != nil {
  // 处理错误
  if errors.Is(err, gorm.ErrRecordNotFound) {
    // 记录未找到
  } else {
    // 其他错误
  }
}

10. 扩展功能

自定义数据类型:

type JSON json.RawMessage
​
// 实现 Scanner 和 Valuer 接口
func (j *JSON) Scan(value interface{}) error {
  // 实现扫描逻辑
}
​
func (j JSON) Value() (driver.Value, error) {
  // 实现值逻辑
}

插件开发:

GORM 提供了插件系统,可以开发自定义插件扩展功能。

11. 常见问题

1. 如何关闭日志?

db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{
  Logger: logger.Default.LogMode(logger.Silent),
})

2. 如何处理软删除?

// 模型包含 gorm.DeletedAt 字段
db.Unscoped().Where("age = 20").Find(&users)
// 查询时会忽略 deleted_at IS NULL 条件
​
db.Unscoped().Delete(&order)
// 永久删除

3. 如何添加表前缀?

db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{
  NamingStrategy: schema.NamingStrategy{
    TablePrefix: "t_", // 表前缀
  },
})

12. 最佳实践

  1. 模型设计

    • 使用结构体标签定义字段属性

    • 合理设计关联关系

    • 考虑使用软删除

  2. 查询优化

    • 只查询需要的字段

    • 合理使用预加载

    • 使用批量操作减少数据库交互

  3. 错误处理

    • 总是检查错误

    • 区分不同类型的错误(记录未找到、连接错误等)

  4. 事务管理

    • 对需要原子性操作的使用事务

    • 避免长事务

  5. 性能监控

    • 使用 GORM 的调试模式检查生成的 SQL

    • 监控慢查询

GORM 是一个功能强大且灵活的 ORM 库,通过合理使用可以大大提高 Go 语言开发中数据库操作的效率和可维护性。

👉 立即点击链接,开启你的全栈开发之路:Golang全栈开发完整课程

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值