Go语言之GORM| 青训营笔记

90 阅读3分钟

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

前言

本文为作者参与青训营学习的课程总结,记录着我对课程内容的收获和思考,以便用于日后的复习查阅。如果所写内容出现不准确的表述或错误,欢迎各位在评论区友好指出。

GORM

一个迭代了10年+的go语言ORM框架,拥有非常丰富的开源扩展

GORM的约定(默认)

  • Gorm会使用名为"ID"的字段作为主键
  • 使用结构体名的蛇形复数形式作为表名,因此如果一个结构体(模型)名为UserInfo,则sql语句中表名会变为user_infos
  • 字段名的蛇形作为列名
  • 使用CreatedAt、UpdatedAt字段作为创建、更新时间

GORM的基础使用

type UserInfo struct {
	Id        int
	Name      string
	Age       int
	CreatedAt time.Time `gorm:"column:created_time"`
	UpdatedAt time.Time `gorm:"column:updated_time"`
        Deleted gorm.DeletedAt `gorm:"column:is_deleted"`
}
// 该方法用于解决蛇形复数形式作为表名导致无法与数据库表匹配的问题
func (receiver UserInfo) TableName() string {
        // 数据库中存在一个名为user_info的表
	return "user_info"
}

连接数据库

dsn := "usr:pwd@tcp(ip:port)/db?charset=utf8mb4&parseTime=true&loc=Local"
db, err := gorm.Open(mysql.Open(dsn),&gorm.Config{})

新增数据

//单个新增
user := UserInfo{Id: 1, Name: "Alice", Age: 18}
db.Create(&user2)

//批量新增
userArr := []UserInfo{{Id: 2, Name: "Tom11", Age: 20}, {Id: 3, Name: "Tom22", Age: 20}}
db.Create(&userArr)

db.Create()传入结构体时要传入结构体的指针

查询数据

// 查询一条数据
var user UserInfo
db.First(&user, 1)
fmt.Println(user)

// 查询多条数据(条件查询)
userSli := make([]UserInfo, 0)
db.Where("age=?", 20).Find(&userSli)
fmt.Println(userSli)
  • First(): 用于查询一条数据,如果无查询结果会报错:ErrRecordNotFound
  • Find():用于查询多条数据,如果无查询结果则不会报错。

当使用结构体作为条件查询时,GORM只会查询表中的非零值字段。我们可以使用map来构建查询条件

更新数据

// 更新单列
db.Model(UserInfo{}).Where("age=?", 20).Update("name", "zhangsan")
// 更新多列
db.Model(UserInfo{}).Where("name=?", "zhangsan").Updates(UserInfo{Name: "lisi", Age: 30})

和查询操作一样,使用结构体更新时,GORM只会更新非零值列。我们可以使用map来构建查询条件或者使用Select(field)来指导需要更新的列

删除数据

  • 物理删除
db.Delete(&UserInfo{}).Where("name like ?", "%zhang")
// delete from user_info where id in(1,2,3)
db.Delete(&UserInfo{}, []int{1, 2, 3})
  • 软删除

数据不会从表中真正被删除,gorm会将DeletedAt字段设置为删除的时间,使其数据不会被正常查询到。如果要使用结构体中要存在 Deleted gorm.DeleteAt

Tips:gorm中crud操作可以使用链式编程,但是在Where()必须写在这些crud操作方法(Create、First、Find...)前

GORM的事务

Gorm提供了Begin、Commit、Rollback方法用于使用事务

手动使用事务

tx := db.Begin()
// 此时需要进行crud操作的话使用tx而不再是db,因为需要在这些数据操作中添加事务操作
tx.Create()
tx.Find()

tx.Rollback()
tx.Commit()

自动提交事务

Gorm提供了Transation方法用于自动提交事务,避免漏写Commit和Rollback

db.Transaction(func(tx *gorm.DB) error {
  // 在事务中执行一些 db 操作(从这里开始,您应该使用 'tx' 而不是 '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
})

GORM Hook

Gorm提供了curd的hook能力。

Hook是在curd操作之前或者之后自动调用的函数(钩子函数) 如果任何Hook返回错误,Gorm将停止后续的操作并回滚事务

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

  if !u.IsValid() {
    return errors.New("can't save invalid data")
  }
  return
}

Gorm性能提高

禁用默认事务

对于写操作(创建、更新、删除),为了确保数据的完整性,GORM 会将它们封装在事务内运行。但这会降低性能,你可以在初始化时禁用这种方式

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

缓存预编译语句

执行任何SQL时都创建并缓存预编译语句,可以提高后续的调用速度

// 全局模式 
db, err := gorm.Open(mysql.Open(dst), &gorm.Config{PrepareStmt: true}) 

// 会话模式 
tx := db.Session(&Session{PrepareStmt: true})

引用

Gorm官网文档(gorm.cn/zh_CN/docs/)