内容概述
本文主要记录一下有关GORM的进阶内容——高级查询和事务操作。
主要内容
使用where查询
查询用户名是zhouzhou
DB.Where("name = ?", "zhouzhou").Find(&users)
查询用户名不是zhouzhou
DB.Where("name <> ?", "zhouzhou").Find(&users)
查询用户名包含zhouzhou,baobao
DB.Where("name in ?", []string{"zhouzhou","baobao"}).Find(&users)
查询姓周的
DB.Where("name like ?", "李%").Find(&users)
查询年龄大于24且是163邮箱
DB.Where("age > ? and email like ?", "24","%@163.com").Find(&users)
查询是女性或者年龄大于24
DB.Where("age > ? and gender = ?", "24", false).Find(&users)
使用结构体查询
使用结构体查询,会过滤零值。并且结构体中的条件都是and关系
DB.Where(&Student{Name: "zhouzhou", Age: 0}).Find(&users)
使用map查询
使用map查询,不会过滤零值
DB.Where(map[string]any{"name": "zhouzhou", "age": 0}).Find(&users)
使用Not查询
排除年龄age大于23岁的
DB.Not("age > 23").Find(&users)
使用or查询
查询年龄等于23岁的,或者邮箱是163邮箱的
DB.Or("age = ?", 23).Or(" email like ?", "%@163.com").Find(&users)
使用select查询
选择name和age两列
DB.Select("name", "age").Find(&users)
使用Order排序
desc表示降序,asc表示升序。根据年龄倒序
DB.Order("age desc").Find(&users)
使用distinct去除重复
去除年龄相同的
DB.Table("students").Select("age").Distinct("age").Scan(&ageList)
DB.Table("students").Select("distinct age").Scan(&ageList)
分组查询
根据性别分组查询
DB.Table("students").Select("count(id)").Group("gender").Scan(&ageList)
子查询
查询大于平均年龄的
DB.Model(Student{}).Where("age > (?)", DB.Model(Student{}).Select("avg(age)")).Find(&users)
事务
事务就是用户定义的一系列数据库操作,这些操作可以视为一个完整的逻辑处理工作单元,要么全部执行,要么全部不执行,是不可分割的工作单元。
为了确保数据一致性,GORM 会在事务里执行写入操作(创建、更新、删除)。如果没有这方面的要求,可以在初始化时禁用它,这将获得大约 30%+ 性能提升。
很形象的一个例子,zhouzhou给baobao转账520元,在程序里面,zhouzhou的余额就要减去520,baobao的余额就要增加520。整个事件具有原子性,是一个整体,哪一步错了,整个事件都是失败的。
以zhouzhou给baobao转账为例,不使用事务的后果。zhouzhou给baobao转账520元,先给zhouzhou减去520,再给baobao增加520
var zhouzhou, baobao User
DB.Take(&zhouzhou, "name = ?", "周周")
DB.Take(&baobao, "name = ?", "包包")
zhouzhou.Money -= 520
DB.Model(&zhouzhou).Update("money", zhouzhou.Money)
baobao.Money += 520
DB.Model(&baobao).Update("money", baobao.Money)
在失败的情况下,假如两者有一方没有成功执行,那么张三白白损失了100,那么李四凭空拿到100元。这显然是不合逻辑的,并且不合法的。 那么,使用事务是怎样的
var zhouzhou, baobao User
DB.Take(&zhouzhou, "name = ?", "周周")
DB.Take(&baobao, "name = ?", "包包")
DB.Transaction(func(tx *gorm.DB) error {
zhouzhou.Money -= 520
err := tx.Model(&zhouzhou).Update("money", zhouzhou.Money).Error
if err != nil {
fmt.Println(err)
return err
}
baobao.Money += 520
err = tx.Model(&baobao).Update("money", baobao.Money).Error
if err != nil {
fmt.Println(err)
return err
}
return nil
})
当然也提供手动事务。开始事务——在事务中执行一些 db 操作——遇到错误时回滚事务——否则,提交事务
tx := db.Begin()
tx.Create(...)
tx.Rollback()
tx.Commit()
以手动事务为例,对上面例子进行修改,如下:zhouzhou给baobao转账520元,先给zhouzhou减去520,再给baobao增加520,最后提交事务
var zhouzhou, baobao User
DB.Take(&zhouzhou, "name = ?", "周周")
DB.Take(&baobao, "name = ?", "包包")
// zhouzhou给baobao转账520元
tx := DB.Begin()
// 先给zhouzhou减去520
zhouzhou.Money -= 520
err := tx.Model(&zhouzhou).Update("money", zhouzhou.Money).Error
if err != nil {
tx.Rollback()
}
// 再给baobao增加520
baobao.Money += 520
err = tx.Model(&baobao).Update("money", baobao.Money).Error
if err != nil {
tx.Rollback()
}
// 提交事务
tx.Commit()
总结
本文主要记录了下GORM的高阶查询和事务操作。高阶查询的where,order,select,or等等,都是mysql相通的,这点很容易上手。事务操作则是为了保持数据一致性,十分重要。