Gorm框架小总结 | 豆包MarsCode AI刷题

82 阅读6分钟

1、Gorm框架

这也是我们上面的小项目中所涉及使用到的框架,是用于操作数据库的一个框架。

这里附上一个GORM框架的中文文档gorm.io/zh_CN/docs/…

安装的话就不过多讲了,自己看文档都是有的

2、链接初始化

  // 参考 https://github.com/go-sql-driver/mysql#dsn-data-source-name 获取详情
  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{})

通过设置dsn,去打开数据库,而且也能够在后边对Config进行相应的数据库连接设置。(包括一些基本设置,以及可以自定义对应的数据库驱动等等)

3、CRUD接口

完成了简单的数据库的初始化之后,我们就可以对数据库进行对应的一系列的操作了,Gorm支持所有对数据库的操作,这里我们也就一一简单介绍一下。

前置

这里要注意的是,使用Gorm对于数据库的操作,针对每个表,我们都需要有个对应的模型结构体去对应数据库的表以及其中的字段。

通俗来说,就是对于数据库操作中,我们习惯性创建一个repository文件夹,启动放置对应数据库有多少表就有多少个文件,一一对应着操作每个表。

并且每个文件中都要定义对应的结构体,也就是如下图所示

// gorm.Model 的定义
type Model struct {
  ID        uint           `gorm:"primaryKey"`
  CreatedAt time.Time
  UpdatedAt time.Time
  DeletedAt gorm.DeletedAt `gorm:"index"`
}

这里注意,如果不使用gorm:"xxxx"去对字段进行申明,结构体字段名称转换为 snake_case 作为数据库中的列名

以及对应表名,我们可以使用Tablename方法去设置func (Post) TableName() string { return "post" },也可以使用默认的所对应命名,也就是将结构体名称转换为 snake_case 并为表名加上复数形式。 例如,一个 User 结构体在数据库中的表名变为 users

并且使用Gorm框架的情况下,我们还能去包含一些特定的字段,实现更好的功能

  • ID :每个记录的唯一标识符(主键)。
  • CreatedAt :在创建记录时自动设置为当前时间。
  • UpdatedAt:每当记录更新时,自动更新为当前时间。
  • DeletedAt:用于软删除(将记录标记为已删除,而实际上并未从数据库中删除)。

基础使用的话这些已经足够了,至于更加高级的,就可以去自己查看官方文档即可。

1、创建

直接使用上面返回的数据库,使用结构体的指针方式去创建对应的数据

user := User{Name: "Jinzhu", Age: 18, Birthday: time.Now()}
result := db.Create(&user) // 通过数据的指针来创建

这里一定要注意,传入的是结构体的指针,而不是单纯的结构体

用着指定的字段创建记录

创建记录并为指定字段赋值。

db.Select("Name", "Age", "CreatedAt").Create(&user)

创建记录并忽略传递给 ‘Omit’ 的字段值

db.Omit("Name", "Age", "CreatedAt").Create(&user)

批量插入

这里批量插入我们使用传入一个切片去完成,或者也可以使用map去创建也是可以的

var users = []User{{Name: "jinzhu1"}, {Name: "jinzhu2"}, {Name: "jinzhu3"}}
db.Create(&users)
db.Model(&User{}).Create(map[string]interface{}{
  "Name": "jinzhu", "Age": 18,
})

2、查询

GORM 提供了 FirstTakeLast 方法,以便从数据库中检索单个对象。当查询数据库时它添加了 LIMIT 1 条件,且没有找到记录时,它会返回 ErrRecordNotFound 错误

image.png

如果你想避免ErrRecordNotFound错误,你可以使用Find,比如db.Limit(1).Find(&user),Find方法可以接受struct和slice的数据。
建议就是尽量使用find而不是first以避免出现一些错误。

根据主键检索

如果主键是数字类型,您可以使用 内联条件 来检索对象。

db.First(&user, 10)
// SELECT * FROM users WHERE id = 10;
db.First(&user, "10")
// SELECT * FROM users WHERE id = 10;
db.Find(&users, []int{1,2,3})
// SELECT * FROM users WHERE id IN (1,2,3);

如果主键是字符串(例如像uuid这种),查询将会被写成如下

db.First(&user, "id = ?", "1b74413f-f3b8-409f-ac47-e8c062e3472a")
// SELECT * FROM users WHERE id = "1b74413f-f3b8-409f-ac47-e8c062e3472a";

检索全部对象

直接通过find去查找即可,这里要注意的是一下的部分

result.RowsAffected // returns found records count, equals `len(users)`
result.Error        // returns error

通过条件检索

String条件

使用Where方法即可

image.png

通过Struct&Map检索

可以通过结构体和Map去达到匹配多项的条件查询的目的

image.png

但这里有一点要注意的就是,使用结构体查询是不会匹配空字符串或者0的,会进行忽略,只有使用map的话才能完成对应的匹配

db.Where(&User{Name: "jinzhu", Age: 0}).Find(&users)
// SELECT * FROM users WHERE name = "jinzhu";
​
db.Where(map[string]interface{}{"Name": "jinzhu", "Age": 0}).Find(&users)
// SELECT * FROM users WHERE name = "jinzhu" AND age = 0;

3、更新

保存所有字段

Save是也贵组合函数。如果保存值不包含主键,它将执行 Create,否则它将执行 Update (包含所有字段)。

db.Save(&User{Name: "jinzhu", Age: 100})
// INSERT INTO `users` (`name`,`age`,`birthday`,`update_at`) VALUES ("jinzhu",100,"0000-00-00 00:00:00","0000-00-00 00:00:00")
​
db.Save(&User{ID: 1, Name: "jinzhu", Age: 100})
// UPDATE `users` SET `name`="jinzhu",`age`=100,`birthday`="0000-00-00 00:00:00",`update_at`="0000-00-00 00:00:00" WHERE `id` = 1

更新单个列

这就很简单了,直接使用update即可。

更新多个列

也是类似,使用结构体和map就行,能够进行多列的更新。

更新所选定的字段

这里可以通过加一些选择进行对应选定字段的更新。

4、删除

最后就是删除了,删除应该算是最简单的了

直接就是可以通过Delete去对某列进行删除。

// 带额外条件的删除
db.Where("name = ?", "jinzhu").Delete(&email)
// DELETE from emails where id = 10 AND name = "jinzhu";

5、原生SLQ的使用

使用Raw和Scan去指定SQL语句

var result Result
db.Raw("SELECT id, name, age FROM users WHERE id = ?", 3).Scan(&result)

Exec原生SQL

// Exec with SQL Expression
db.Exec("UPDATE users SET money = ? WHERE name = ?", gorm.Expr("money * ? + ?", 10000, 1), "jinzhu")

4、事务

禁用默认事务

为了确保数据一致性,GORM 会在事务里执行写入操作(创建、更新、删除)。如果没有这方面的要求,您可以在初始化时禁用它,这将获得大约 30%+ 性能提升。

可以通过SkipDefaultTransaction对应配置去关闭

手动事务

Gorm 支持直接调用事务控制方法(commit、rollback),例如:

// 开始事务
tx := db.Begin()
// 在事务中执行一些 db 操作(从这里开始,您应该使用 'tx' 而不是 'db')
tx.Create(...)
// ...
// 遇到错误时回滚事务
tx.Rollback()
// 否则,提交事务
tx.Commit()

这样差不多,Gorm的使用我们大致也就了解了,接下来就是让我们进入Kitex的学习!

自动提交事务

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

5、Gorm生态

GORM 代码生成工具github.com/go-gorm/gen
GORM 分片库方案github.com/go-gorm/sha…
GORM 手动索引github.com/go-gorm/hin…
GORM 乐观锁github.com/go-gorm/opt…
GORM 读写分离github.com/go-gorm/dbr…
GORM OpenTelemetry扩展github.com/go-gorm/ope…

关于更多的GORM用法可以查看Gorm的文档(gorm.cn)