这是我参与「第五届青训营」伴学笔记创作活动的第 8 天
GORM 简介
特性
- 全功能 ORM
- 关联 (Has One,Has Many,Belongs To,Many To Many,多态,单表继承)
- Create,Save,Update,Delete,Find 中钩子方法
- 支持
Preload、Joins的预加载 - 事务,嵌套事务,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 可以让查询和删除这两条语句不会互相干扰。