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. 最佳实践
-
模型设计:
-
使用结构体标签定义字段属性
-
合理设计关联关系
-
考虑使用软删除
-
-
查询优化:
-
只查询需要的字段
-
合理使用预加载
-
使用批量操作减少数据库交互
-
-
错误处理:
-
总是检查错误
-
区分不同类型的错误(记录未找到、连接错误等)
-
-
事务管理:
-
对需要原子性操作的使用事务
-
避免长事务
-
-
性能监控:
-
使用 GORM 的调试模式检查生成的 SQL
-
监控慢查询
-
GORM 是一个功能强大且灵活的 ORM 库,通过合理使用可以大大提高 Go 语言开发中数据库操作的效率和可维护性。
👉 立即点击链接,开启你的全栈开发之路:Golang全栈开发完整课程