Gorm 学习笔记-2
这篇笔记紧跟第一篇的内容,继续学习 Gorm 的相关操作。此外,GORM 官方中文文档也写得非常详细,这篇笔记大多参考官方文档,并在其基础上适当精炼。上一篇笔记我们进行到连接数据库,这一篇我们跳过无聊的 CURD 操作。
不过值得注意的是,在使用 Where 进行查询时,Gorm 仅会查询非零值,这意味着数据库中的 0、false、’ ’ 等值不会被查询到。如果有字段为上述值,也不会用于构建查询条件。譬如:
db.Where(&User{Name: "zzh0u", Age: 0}).Find(&users)
// 执行 SELECT * FROM users WHERE name = "zzh0u";
// 而非 SELECT * FROM users WHERE name = "zzh0u" AND age = 0;
如果要在查询条件中包含零值,可以使用 map 来查询,这样将包含所有键值作为查询条件。譬如:
db.Where(map[string]interface{}{"name": "zzh0u", "age": 0}).Find(&users)
// 执行 SELECT * FROM users WHERE name = "zzh0u" AND age = 0;
事务处理
事务确保一系列数据库操作要么全部成功,要么全部失败。Gorm 提供了简单的事务支持。
基本事务
// 开始事务
tx := db.Begin()
// 在事务中执行数据库操作
if err := tx.Create(&user).Error; err != nil {
// 发生错误时回滚事务
tx.Rollback()
return err
}
if err := tx.Create(&profile).Error; err != nil {
tx.Rollback()
return err
}
// 提交事务
return tx.Commit().Error
使用事务闭包
Gorm 也支持使用闭包进行事务处理,更加简洁:
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
}
// 返回nil提交事务
return nil
})
高级查询技巧
子查询
子查询允许在一个查询中嵌套另一个查询:
// 查找发表文章数量大于5的用户
db.Where("id IN (?)", db.Table("articles").Select("user_id").Group("user_id").Having("count(*) > ?", 5)).Find(&users)
原生SQL
有时需要执行原生SQL查询:
// 执行原生SQL
db.Raw("SELECT id, name FROM users WHERE age > ?", 20).Scan(&result)
// 执行SQL并获取第一条结果
db.Raw("SELECT name FROM users WHERE id = ?", 1).Scan(&name)
性能优化
批量插入
批量插入比单条插入效率高:
var users = []User{
{Name: "张三"},
{Name: "李四"},
{Name: "王五"},
}
// 一次插入多条记录
db.Create(&users)
索引提示
Gorm 允许在查询时使用索引提示:
// 使用索引提示
db.Clauses(hints.UseIndex("idx_user_name")).Where("name = ?", "张三").Find(&users)