[ GORM框架基础 | 青训营笔记]

82 阅读4分钟

这是我参与「第五届青训营 」伴学笔记创作活动的第 3 天

Gorm框架

官方文档

基本使用

定义数据模型 与 数据表名:

type Product struct{
    Code string
    Price uint
}
​
//为数据模型定义表的名字
func (p Product) TableName() string{
    return "product"
}

对于数据模型与其对应的数据表和字段,gorm有如下的默认约定:

  • 使用名字为ID的字段作为表的主键
  • 使用结构体的蛇形复数作为表名(例如表名visit_logs
  • 使用字段的蛇形作为列名
  • 使用CreateAt和UpdateAt两个字段来跟踪对象创建和修改的时间

可以使用结构体的tag来指定字段对应的列名,以及默认值等。

连接到数据库:

gorm支持多种类型的数据库(MySql,PostgreSql,SQlite和SQL Server),通过给对应的驱动程序传递一个dsn的方式打开连接

import(
  "gorm.io/driver/mysql"
  "gorm.io/gorm"
)
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{})
}

对于数据库连接池,GORM使用标准库的database/sql维护

创建数据

使用db.Create(&User{Name:"Jim", Age: 18})来在数据库中创建一条记录。

注意db.Create被调用是,这条Sql已经生成了,因此无法在它后面加.Where字句作为条件,如果需要解决冲突,使用如下的形式:

db.Clause(clause.OnConflict{DoNothing: true}).Create(&p)

查询

  • 检索单个对象

    GORM提供First/Take/Last三个方法从数据库中检索单个对象,分别对应主键升序第一条记录、未排序的一条记录和主键升序的最后一条记录。这三个方法会为生成的SQL添加LIMIT 1条件。

    对于传入的参数,如果主键已经被设置了,那么会使用主键作为查询条件。

    db.First(&user)
    db.Take(&user)
    db.Last(&user)
    

    也可以传入额外的参数作为查询条件。

    • First方法的一个坑点是:如果查询不到数据时,会返回ErrRecordNotFound
  • 检索全部对象

    使用db.Find检索全部的对象。在查询不到数据时不会返回数据。

    var users []User
    db.Find(&users)
    
  • 增加检索条件

    使用db.Where方法来为一条查询语句增加检索条件。

更新数据

  • 更新单个字段

    使用db.Model(&user).Update(“name", "hello")来更新数据,即这条语句会根据user的主键(如果存在非零的主键ID)找到并更新对应记录的name字段为hello

    使用Model是为了传递数据表名数据。

  • 更新多个字段

    使用db.Model(&user).Updates(map[string]any{"name":"hello", "age": 0})来同时更新多个字段值。

    需要注意的是如果给Updates传入的参数是结构体而不是map,那么其中的零值是不会更新的。

删除数据

使用db.Delete(&user, conds...)来删除字段。

如果在数据模型中增加一个Deleted gorm.DeletedAt字段,可以实现数据的软删除

软删除的数据不会从数据库中真正删除,但是用GORM的常规查询方法无法再查询到软删除的数据,需要使用Unscoped来查询被软删除的数据。

事务处理

GORM提供了BeginCommitRollback方法用于处理事务。

一个例子如下:

tx := db.Begin() // 开始事务处理
if err:= tx.Create(&User{Name:"name"}).Error; err!= nil{
    tx.Rollback()
    return
}
if err:= tx.Create(&User{Name:"name2"}).Error; err!= nil{
    tx.Rollback()
    return 
}
tx.Commit()

事务的自动处理

如果使用GORM提供的Transaction方法,可以自动提交事务,避免漏掉Commit和Rollback

推荐使用Transaction方法来代替上述的Begin/Commit/Rollback手动调用,以减少错误的发生

Hook

给结构体增加类似于BeforeCreate(tx *gorm.DB)(err error)方法来提供在对象的增删改查前后自动调用的函数。

GORM会给Hook提供一个默认事务,因此任何Hook返回错误时,GORM会停止后续操作并回滚事务。

提高性能的手段

  • 关闭事务处理

    对于数据的写操作,为了保证数据的完整性,GORM默认会将它们封装到事务内运行。

    可以使用SkipDefaultTransaction来关闭默认事务

  • 使用PrepareStmt缓存预编译语句

    可以提高后续的调用大约35%的性能。

GORM扩展

  • 代码生成
  • 分片
  • 手动索引
  • 乐观锁
  • 读写分离

都在github.com/go-gorm下有对应的仓库。