Gorm、KiteX、Hertz框架(2) | 青训营笔记

95 阅读6分钟

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

接上文。

这里主要讲一下增删改查,和查询条件设置的部分。还有部分可能会需要使用到的高级用法。

gorm给了两个查询的方法分别是First和Find两个方法。

First只会查询一条记录,有多条记录的话会返回第一条,而且如果没有查询到对应记录的话,就会报错。(其实就相当于添加了一个limit 1的操作,和未查询到结果报错)

而Find则是我们经常使用的查询操作了,就和我们正常使用sql一样。他会返回查询的所有数据(如果没有限制条件的话)。

在使用这两个方式时,我们都需要传入一个引用的对象。我们的查询到的数据将会反序列化到我们提供的变量中。

所以对于First方法,我们需要传入一个结构体的引用,而对于Find我们则需要传入一个结构体切片的引用。

var user pms
var users []pms
db.First(&user)
db.Find(&users)

添加记录使用的是Create方法:

res := db.Create(&table{Name: "User1", Phone: 1231232})

var user = table{Name: "User1", Phone: 1231232}
res:= db.Create{&table}

如果你想要一次性插入多个数据,只需要传入切片的引用即可。当然你也可以使用CreateInBatches方法来进行批量操作。

你可能会疑惑为什么创建我们也要传入引用。这是因为,gorm有一些默认的字段。例如我们的创建时间,这个是由系统自动生成的,所以他会存在写回的情况。所以我们需要传入一个引用。

删除记录使用的是Delete方法。

res := db.Delete(&table{Name: "User1", Phone: 1231232})

Delete方法会根据设定的主键来进行删除操作,所以如果你没有gorm默认的ID字段的话,你需要指定一下那个字段是你的主键。否则会报错缺少条件。

更新记录使用Update方法:

res := db.Model(&table{}).Update("name", "newName")

这里需要注意的是,和之前的不同,我们需要使用Model这个方法,告诉Update的表是怎么样的。这里我是直接创建了一个空记录,来提供结构。这样子这条语句是无法执行的。因为我们没有给条件。

user := table{Phone: 1231232}
res := db.Model(&user).Update("name", "newName")

这里,我们就在告知表结构的同时,将我们的主键约束(我这里是我的Phone字段)也告知了gorm,gorm就会根据这个条件来生成对应的sql。当然,我们第一种方式也是可以用的,这部分内容会放在下面讲。

map in Create

我们的增删改查的很多结构都支持map[string]interface{}的参数结构。这使得我们的可以更加精确的传入我们的参数。正常来说,0值和空值将会被gorm忽略而不进入到sql中,如果使用map,gorm将不会忽略0值与空值。

在Create中,我们可以使用map来批量指定创建:

res := db.Model(&table{}).Create([]map[string]interface{}{
   {"name": "User3", "phone": "123123342"},
   {"name": "User4", "phone": ""},
})

由于我们使用的interface是没有结构的,所以这里我们需要model来说明结构。注意这里就是字典形式了。名称需要和字段名一致。

当然你也可以用map来插入单个:

db.Model(&table{}).Create(map[string]interface{}{"name": "User5", "phone": 0})

Where

Where其实就是我们Sql中的条件。我们可以像Model那样的形式去使用Where,例如下面这个例子:

var user table
db.Where("name = ?", "User1").First(&user)

这里我们就指定了要查询name为User1的记录。这里面具体的User1不能直接写到query里面。Where还可以使用map或者struct来做条件。

db.Where(&table{Name: "User1"}).First(&user)
db.Where(map[string]interface{}{"name": "User1"}).First(&user)
db.Where([]string{"User1", "User2", "User3"}).Find(&users)

第一条与第二条都是查询name为User1的记录。 而第三条则是主键是否在提供的切片中,也就是where phone in (User1,User2,User3)。一般传入切片作为条件都是判断是否在这个集合中。

Where方法不仅仅用在select中,在所有需要限定的地方都可以使用,例如你要删除记录,可以用Where选择条件。

当你使用前两种方法的时候,你是可以指定这些参数是参与条件组成的。

db.Where(map[string]interface{}{"name": "User1", "phone": "00000"}, "name").First(&user)

在这个例子中,我们虽然提供了phone字段的具体信息,但是我们指定我们只需要其中的name字段来进行where条件的组合。而phone就被我们忽略了。

内联条件

上面我们说使用Where来设置条件。但其实我们也可以直接在相应的操作函数中写上条件,而这种我们称为内联条件:

db.First(&user, "name = ?", "User1")
db.Find(&users, "name in ?", []string{"User1", "User2", "User3"})

Model

Model是gorm内置一个struct。里面包含了一些gorm默认的字段。

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

gorm默认使用名为ID的字段作为primaryKey。如果你有其他的打上了primaryKey标签的字段将会使用你设置的字段作为主键。ID也是gorm的自增主键,而剩下三个是和操作标记相关的字段。

事务

说到数据库就离不开事务的操作。

我们的基本的增删改查在gorm中是默认为事务的。也就是我们每次增删改查都是开启了一个事务并commit。当然你也可以在设置中关闭这个选项。只需要在开启时传入的config中加入SkipDefaultTransaction: true键值对即可。可以获得30%的性能提升。

gorm提供了手动的事务管理以及自动的事务管理。

tx := db.Begin()
tx.Create(&table{"User6", 12354151})
// do something
tx.Commit()

我觉得还是将手动管理的事务写成函数比较好,因为在函数中我们可以使用defer来确保我们的事务可以commit。

而另一个自动的事务管理就是我们的Transaction方法。

db.Transaction(func(tx *gorm.DB) error {
   if err := tx.Create(&table{"User8", 23123}).Error; err != nil {
      return err
   }
   return nil // commit
})

需要注意的一点是,我们开启事务之后,需要通过返回的tx来进行数据库的操作,而不是db。