GORM 的入门学习和使用 | 青训营笔记

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

GORM 简介

特性

  • 全功能 ORM
  • 关联 (Has One,Has Many,Belongs To,Many To Many,多态,单表继承)
  • Create,Save,Update,Delete,Find 中钩子方法
  • 支持 PreloadJoins 的预加载
  • 事务,嵌套事务,Save Point,Rollback To Saved Point
  • Context、预编译模式、DryRun 模式
  • 批量插入,FindInBatches,Find/Create with Map,使用 SQL 表达式、Context Valuer 进行 CRUD
  • SQL 构建器,Upsert,数据库锁,Optimizer/Index/Comment Hint,命名参数,子查询
  • 复合主键,索引,约束
  • Auto Migration
  • 自定义 Logger
  • 灵活的可扩展插件 API:Database Resolver(多数据库,读写分离)、Prometheus…
  • 每个特性都经过了测试的重重考验
  • 开发者友好

以上介绍来自官方文档,简单来说,GORM是一个易于使用的操作数据库的库。

安装

使用 go get 安装。

go get -u gorm.io/gorm

基本使用方法(CRUD)

创建一个数据库实例

db, err : = gorm.Open(mysql.New(mysqlConfig))
if err != nil {
    panic("DB Connection error")
}

数据库模型

数据库模型是一个结构体,用于指定操作哪张表,结构体的成员代表字段。

// User 用户数据库模型
type User struct {
	gorm.Model
	Username      string `json:"username" gorm:"comment:用户登录名"`      // 用户登录名
	Password      string `json:"-"  gorm:"comment:用户登录密码"`           // 用户登录密码
}

其中gorm.Model是GORM库推荐的几个字段,分别是ID,CreatedAt,UpdatedAt,DeletedAt

创建

创建是使用 GROM 在表中插入一行,实际使用了 INSERT 语句。

user := &User{
    Username: "abc",
    password: "123",
}
if err := db.Model(&User{}).Create(user).Error; err != nil{
    return err
}

Model 指定了使用了哪张表,user将数据传入,GORM就会在表中创建新行。

创建成功后可以从user中拿到ID,即主键。

查询

查询可以使用 Where 方法指定查询特定字段,或者在指定范围内查询。

First 用于查询按主键升序的第一条符合的数据。查询不到时返回 ErrRecordNotFound 错误。可以利用这个错误判断数据在不在数据库中。

if err := db.Model(&User{}).Where("user_name = ?", "a").First(&user).Error; err!= nil{
    return err
}

Find 用于查询一组数据。

if err := db.Model(&User{}).Where("user_name = ?", "a").Find(&users).Error; err!= nil{
    return err
}

根据主键查询则更加简单,依然是First查询第一个数据,Find查询一组数据。

db.First(&user, 1)
db.Find(&users, []int{1,2,3})

更新

在使用 Find 和 First 查询到数据后,使用Save方法保存,即可完成更新。

db.First(&user)
user.Username = "aa"
user.Password = "100"
db.Save(&user)

删除

使用 Where 查询语句后面跟上 Delete 即可删除符合条件的数据。

db.Where("user_name = ?", "abc").Delete(&user)

和查询类似,可以使用主键删除数据。

db.Where("user_name = ?", "abc").Delete(&User{},2)
db.Where("user_name = ?", "abc").Delete(&User{},[]int{1,2,3})

传递整数类型切片可以删除多个数据。

项目中的使用

事务

当一次需要对多个数据表进行写入和修改时,需要注意到数据一致性问题,我们可以使用事务来解决。

使用 Transaction 方法来使用事务.

db.Transaction(func(tx *gorm.DB) error {
    if err := tx.WithContext(ctx).Model(&Comment{}).Delete(&Comment{}, comment.ID).Error; err != nil {
        return err
    }
    return nil
})

事务中应该使用 tx 替换原来的 db。

上下文

由于 GORM 是支持链式操作的,连续使用查询语句会造成混乱,解决方法是使用 context。

if err := db.WithContext(ctx).Model(&Video{}).First(comment, comment.ID).Error; err != nil{
    return err
}
if err := db.WithContext(ctx).Model(&Comment{}).Delete(&Comment{}, comment.ID).Error; err != nil {
    return err
}

使用 context 可以让查询和删除这两条语句不会互相干扰。