一篇来自ORM的整理笔记…

1 什么是ORM?为什么要⽤ORM?

什么是ORM ,即Object-Relationl Mapping,它的作⽤是在关系型数据库和对象之间作⼀个映射,

这样,我们在具体的 操作数据库的时候,就不需要再去和复杂的SQL语句打交道,只要像平时操作对象⼀样操作它就可以了 。

ORM解决的主要问题是对象关系的映射。域模型和关系模型分别是建⽴在概念模型的基础上的。

  • 域模型是⾯向对 象的

  • 关系模型是⾯向关系的

⼀般情况下,⼀个持久化类和⼀个表对应,类的每个实例对应表中的⼀条记录,

类的每个属性对应表的每个字段。

ORM技术特点:

  • 提⾼了开发效率

    由于ORM可以⾃动对Entity对象与数据库中的Table进⾏字段与属性的映射,所以我们实际 可能已经不需要⼀个专⽤的、庞⼤的数据访问层。

  • ORM提供了对数据库的映射,不⽤sql直接编码,能够像操作对象⼀样从数据库获取数据。

ORM的缺点

ORM的缺点是会牺牲程序的执⾏效率和会固定思维模式

从系统结构上来看,采⽤ORM的系统⼀般都是多层系统,系统的层次多了,效率就会降低。ORM是⼀种完全的 ⾯向对象的做法,⽽⾯向对象的做法也会对性能产⽣⼀定的影响。

2 ORM操作数据

 1package main
2
3import (
4    "fmt"
5    "github.com/jinzhu/gorm"
6    _ "github.com/jinzhu/gorm/dialects/mysql"
7)
8
9// UserInfo 用户信息
10//orm会默认根据结构体创建table , orm采用的是linux命名方式  即小写加下划线,且会在名字后面加 s
11//会创建user_infos 表
12type UserInfo struct {
13    gorm.Model
14    ID     uint
15    Name   string
16    Gender string
17    Hobby  string
18}
19
20//  truncate table 表名
21//  数据库需要提前创建好  例如mygorm
22//  parseTime是查询结果是否⾃动解析为时间
23//  loc是MySQL的时区设置
24//  charset是编码方式
25func main() {
26    fmt.Println("try open mysql connection....")
27    db, err := gorm.Open("mysql""root:123456@(localhost:3306)/mygorm?charset=utf8mb4&parseTime=True&loc=Local")
28    if err != nil {
29        panic(err)
30    }
31    fmt.Println("successful")
32    defer db.Close()
33    // 自动迁移
34    //若该表不存在则创建该表,若该表存在且结构体发生变化则更新表结构
35    db.AutoMigrate(&UserInfo{})
36    u1 := UserInfo{gorm.Model{}, 1"xiaozhu""man""playing"}
37    // 创建记录
38    result := db.Create(&u1)
39    fmt.Println("result:", result.RowsAffected)
40    // 查询
41    var u = new(UserInfo)
42    //查询一条记录
43    db.First(u)
44    fmt.Printf("First: %#v\n", u)
45    //按照条件查询
46    var uu UserInfo
47    db.Find(&uu, "name=?""xiaozhu")
48    fmt.Printf("Find: %#v\n", uu)
49    // 更新
50    db.Model(&uu).Update("hobby""sing")
51    // 删除 , 此处删除记录,是不会将数据表中的数据删除掉,而是deleted_at 会更新删除时间
52    db.Delete(&uu)
53}
  • 使用gorm必须要先创建好数据库

  • gorm会自动创建数据表,且表结构可以动态变化

  • gorm创建的表命名方式为 代码中结构体命名的转换, 例如 结构体命名为UserInfo,则table会命名为user_infos

  • gorm修改表结构非常的容易

  • gorm是完全面向对象的思想

3 模型定义

模型是标准的 struct,由 Go 的基本数据类型、实现了 Scanner 和 Valuer 接口的自定义类型及其指针或别名组成

例如:

 1type User struct {
2  ID           uint
3  Name         string
4  Email        *string
5  Age          uint8
6  Birthday     *time.Time
7  MemberNumber sql.NullString
8  ActivatedAt  sql.NullTime
9  CreatedAt    time.Time
10  UpdatedAt    time.Time
11}

自定义模型

遵循 GORM 已有的约定,可以减少您的配置和代码量。

 1type User struct {
2   gorm.Model   // 内嵌
3   Name         string
4   Age          sql.NullInt64
5   Birthday     *time.Time
6   Email        string  `gorm:"type:varchar(100);uniqueIndex"`
7   Role         string  `gorm:"size:255"`        // 设置字段大小为255
8   MemberNumber *string `gorm:"unique;not null"` // 设置会员号(member number)唯一并且不为空
9   Num          int     `gorm:"AUTO_INCREMENT"`  // 设置 num 为自增类型
10   Address      string  `gorm:"index:addr"`      // 给address字段创建名为addr的索引
11   IgnoreMe     int     `gorm:"-"`               // 忽略本字段
12}

字段标签

声明 model 时,tag 是可选的,GORM 支持以下 tag:tag 名大小写不敏感,但建议使用 camelCase 风格

标签名说明
column指定 db 列名
type列数据类型,推荐使用兼容性好的通用类型,例如:所有数据库都支持 bool、int、uint、float、string、time、bytes 并且可以和其他标签一起使用,例如:not nullsizeautoIncrement… 像 varbinary(8) 这样指定数据库数据类型也是支持的。在使用指定数据库数据类型时,它需要是完整的数据库数据类型,如:MEDIUMINT UNSIGNED not NULL AUTO_INSTREMENT
size指定列大小,例如:size:256
primaryKey指定列为主键
unique指定列为唯一
default指定列的默认值
precision指定列的精度
scale指定列大小
not null指定列为 NOT NULL
autoIncrement指定列为自动增长
autoIncrementIncrement自动步长,控制连续记录之间的间隔
embedded嵌套字段
embeddedPrefix嵌入字段的列名前缀
autoCreateTime创建时追踪当前时间,对于 int 字段,它会追踪秒级时间戳,您可以使用 nano/milli 来追踪纳秒、毫秒时间戳,例如:autoCreateTime:nano
autoUpdateTime创建/更新时追踪当前时间,对于 int 字段,它会追踪秒级时间戳,您可以使用 nano/milli 来追踪纳秒、毫秒时间戳,例如:autoUpdateTime:milli
index根据参数创建索引,多个字段使用相同的名称则创建复合索引,查看 索引 获取详情
uniqueIndex与 index 相同,但创建的是唯一索引
check创建检查约束,例如 check:age > 13,查看 约束 获取详情
<-设置字段写入的权限, <-:create 只创建、<-:update 只更新、<-:false 无写入权限、<- 创建和更新权限
->设置字段读的权限,->:false 无读权限
-忽略该字段,- 无读写权限
comment迁移时为字段添加注释

关联标签

标签描述
foreignKey指定当前模型的列作为连接表的外键
references指定引用表的列名,其将被映射为连接表外键
polymorphic指定多态类型,比如模型名
polymorphicValue指定多态值、默认表名
many2many指定连接表表名
joinForeignKey指定连接表的外键列名,其将被映射到当前表
joinReferences指定连接表的外键列名,其将被映射到引用表
constraint关系约束,例如:OnUpdateOnDelete

4 主键、表名、列名的约定

主键(Primary Key)

GORM 默认会使⽤名为ID的字段作为表的主键。

1 type User struct { 
2
3 ID string // 名为`ID`的字段会默认作为表的主键 
4
5 Name string 
6
7 }
 1// 使⽤`AnimalID`作为主键 
2
3type Animal struct { 
4
5AnimalID int64 `gorm:"primary_key"` 
6
7Name string 
8
9Age int64 
10
11

表名(Table Name)

表名默认就是结构体名称的复数,例如:

 1type User struct {} // 默认表名是 `users` 
2
3// 将 User 的表名设置为 `profiles` 
4
5func (User) TableName() string { 
6
7    return "profiles" 
8
9
10
11func (u User) TableName() string { 
12
13    if u.Role == "admin" { 
14
15        return "admin_users" 
16
17    } else { 
18
19        return "users" 
20
21    } 
22
23
24
25// 禁⽤默认表名的复数形式,如果置为 true,则 `User` 的默认表名是 `user` 
26
27db.SingularTable(true

也可以通过 Table() 指定表名:

 1// 使⽤User结构体创建名为`deleted_users`的表 
2
3db.Table("deleted_users").CreateTable(&User{}) 
4
5var deleted_users []User 
6
7db.Table("deleted_users").Find(&deleted_users) 
8
9// SELECT * FROM deleted_users; 
10
11db.Table("deleted_users").Where("name = ?""jinzhu").Delete() 
12
13// DELETE FROM deleted_users WHERE name = 'jinzhu'; 

GORM还⽀持更改默认表名称规则:

1gorm.DefaultTableNameHandler = func (db *gorm.DB, defaultTableName string) string { 
2     return "prefix_" + defaultTableName;
3

列名(Column Name)

列名由字段名称进⾏下划线分割来⽣成

 1type User struct { 
2
3ID uint // column name is `id` 
4
5Name string // column name is `name` 
6
7Birthday time.Time // column name is `birthday` 
8
9CreatedAt time.Time // column name is `created_at` 
10
11

可以使⽤结构体tag指定列名:

1type Animal struct { 
2
3AnimalId int64 `gorm:"column:beast_id"` // set column name to `beast_id` 
4
5Birthday time.Time `gorm:"column:day_of_the_beast"` // set co lumn name to `day_of_the_beast` 
6
7Age int64 `gorm:"column:age_of_the_beast"` // set column name to `age_of_the_beast` 
8
9

时间戳跟踪

CreatedAt

如果模型有 CreatedAt 字段,该字段的值将会是初次创建记录的时间。

1db.Create(&user) // `CreatedAt`将会是当前时间 
2
3// 可以使⽤`Update`⽅法来改变`CreateAt`的值 
4
5db.Model(&user).Update("CreatedAt", time.Now()) 

UpdatedAt

如果模型有 UpdatedAt 字段,该字段的值将会是每次更新记录的时间。

1db.Save(&user) // `UpdatedAt`将会是当前时间 
2
3db.Model(&user).Update("name""jinzhu"// `UpdatedAt`将会是当前时间 

DeletedAt

如果模型有 DeletedAt 字段,调⽤ Delete 删除该记录时,将会设置 DeletedAt 字段为当前时间,⽽

不是直接将记录从数据库中删除。

5 CURD

创建记录

1user := User{Name: "Jinzhu", Age: 18, Birthday: time.Now()}
2
3result := db.Create(&user) // 通过数据的指针来创建
4
5user.ID             // 返回插入数据的主键
6result.Error        // 返回 error
7result.RowsAffected // 返回插入记录的条数

批量插入

要有效地插入大量记录,请将一个 slice 传递给 Create 方法。将切片数据传递给 Create 方法,GORM 将生成一个单一的 SQL 语句来插入所有数据,并回填主键的值,钩子方法也会被调用。

1var users = []User{{Name: "jinzhu1"}, {Name: "jinzhu2"}, {Name: "jinzhu3"}}
2db.Create(&users)
3
4for _, user := range users {
5  user.ID // 1,2,3
6}

使用 CreateInBatches 创建时,你还可以指定创建的数量,例如:

1var users = []User{{name: "jinzhu_1"}, ...., {Name: "jinzhu_10000"}}
2
3// 数量为 100
4db.CreateInBatches(users, 100)

默认值

您可以通过标签 default 为字段定义默认值,如:

1type User struct {
2  ID   int64
3  Name string `gorm:"default:galeone"`
4  Age  int64  `gorm:"default:18"`
5}

插入记录到数据库时,默认值 会被用于 填充值为 零值 的字段

查询

检索单个对象

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

 1// 获取第一条记录(主键升序)
2db.First(&user)
3// SELECT * FROM users ORDER BY id LIMIT 1;
4
5// 获取一条记录,没有指定排序字段
6db.Take(&user)
7// SELECT * FROM users LIMIT 1;
8
9// 获取最后一条记录(主键降序)
10db.Last(&user)
11// SELECT * FROM users ORDER BY id DESC LIMIT 1;
12
13result := db.First(&user)
14result.RowsAffected // 返回找到的记录数
15result.Error        // returns error
16
17// 检查 ErrRecordNotFound 错误
18errors.Is(result.Error, gorm.ErrRecordNotFound)

如果你想避免ErrRecordNotFound错误,你可以使用Find,比如db.Limit(1).Find(&user)Find方法可以接受struct和slice的数据。

FirstLast方法将按主键排序查找第一/最后一条记录,只有在用struct查询或提供model value时才有效,如果当前model没有定义主键,将按第一个字段排序,例如:

 1var user User
2var users []User
3
4// 可以
5db.First(&user)
6// SELECT * FROM `users` ORDER BY `users`.`id` LIMIT 1
7
8// 可以
9result := map[string]interface{}{}
10db.Model(&User{}).First(&result)
11// SELECT * FROM `users` ORDER BY `users`.`id` LIMIT 1
12
13// 不行
14result := map[string]interface{}{}
15db.Table("users").First(&result)
16
17// 但可以配合 Take 使用
18result := map[string]interface{}{}
19db.Table("users").Take(&result)
20
21// 根据第一个字段排序
22type Language struct {
23  Code string
24  Name string
25}
26db.First(&Language{})
27// SELECT * FROM `languages` ORDER BY `languages`.`code` LIMIT 1

用主键检索

如果主键是数值类型,也可以通过 内联条件 传入主键来检索对象。如果主键是 string 类型,要小心避免 SQL 注入,查看 安全 获取详情

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

如果主键是像 uuid 这样的字符串,您需要这要写:

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

检索全部对象

1// 获取全部记录
2result := db.Find(&users)
3// SELECT * FROM users;
4
5result.RowsAffected // 返回找到的记录数,相当于 `len(users)`
6result.Error        // returns error

条件

String 条件
 1// 获取第一条匹配的记录
2db.Where("name = ?""jinzhu").First(&user)
3// SELECT * FROM users WHERE name = 'jinzhu' ORDER BY id LIMIT 1;
4
5// 获取全部匹配的记录
6db.Where("name <> ?""jinzhu").Find(&users)
7// SELECT * FROM users WHERE name <> 'jinzhu';
8
9// IN
10db.Where("name IN ?", []string{"jinzhu""jinzhu 2"}).Find(&users)
11// SELECT * FROM users WHERE name IN ('jinzhu','jinzhu 2');
12
13// LIKE
14db.Where("name LIKE ?""%jin%").Find(&users)
15// SELECT * FROM users WHERE name LIKE '%jin%';
16
17// AND
18db.Where("name = ? AND age >= ?""jinzhu""22").Find(&users)
19// SELECT * FROM users WHERE name = 'jinzhu' AND age >= 22;
20
21// Time
22db.Where("updated_at > ?", lastWeek).Find(&users)
23// SELECT * FROM users WHERE updated_at > '2000-01-01 00:00:00';
24
25// BETWEEN
26db.Where("created_at BETWEEN ? AND ?", lastWeek, today).Find(&users)
27// SELECT * FROM users WHERE created_at BETWEEN '2000-01-01 00:00:00' AND '2000-01-08 00:00:00';

Struct & Map 条件

 1// Struct
2db.Where(&User{Name: "jinzhu", Age: 20}).First(&user)
3// SELECT * FROM users WHERE name = "jinzhu" AND age = 20 ORDER BY id LIMIT 1;
4
5// Map
6db.Where(map[string]interface{}{"name""jinzhu""age"20}).Find(&users)
7// SELECT * FROM users WHERE name = "jinzhu" AND age = 20;
8
9// 主键切片条件
10db.Where([]int64{202122}).Find(&users)
11// SELECT * FROM users WHERE id IN (20, 21, 22);

注意 当使用结构作为条件查询时,GORM 只会查询非零值字段。这意味着如果您的字段值为 0''false 或其他 零值,该字段不会被用于构建查询条件,例如:

1db.Where(&User{Name: "jinzhu", Age: 0}).Find(&users)
2// SELECT * FROM users WHERE name = "jinzhu";

你可以使用 map 来构建查询条件,它会使用所有的值,例如:

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

或查看 指定结构体查询字段 获取详情

指定结构体查询字段

当使用结构体进行查询时,你可以使用它的字段名或其 dbname 列名作为参数来指定查询的字段,例如:

1db.Where(&User{Name: "jinzhu"}, "name""Age").Find(&users)
2// SELECT * FROM users WHERE name = "jinzhu" AND age = 0;
3
4db.Where(&User{Name: "jinzhu"}, "Age").Find(&users)
5// SELECT * FROM users WHERE age = 0;

内联条件

用法与 Where 类似

 1// SELECT * FROM users WHERE id = 23;
2// 根据主键获取记录,如果是非整型主键
3db.First(&user, "id = ?""string_primary_key")
4// SELECT * FROM users WHERE id = 'string_primary_key';
5
6// Plain SQL
7db.Find(&user, "name = ?""jinzhu")
8// SELECT * FROM users WHERE name = "jinzhu";
9
10db.Find(&users, "name <> ? AND age > ?""jinzhu"20)
11// SELECT * FROM users WHERE name <> "jinzhu" AND age > 20;
12
13// Struct
14db.Find(&users, User{Age: 20})
15// SELECT * FROM users WHERE age = 20;
16
17// Map
18db.Find(&users, map[string]interface{}{"age"20})
19// SELECT * FROM users WHERE age = 20;

Not 条件

构建 NOT 条件,用法与 Where 类似

 1db.Not("name = ?""jinzhu").First(&user)
2// SELECT * FROM users WHERE NOT name = "jinzhu" ORDER BY id LIMIT 1;
3
4// Not In
5db.Not(map[string]interface{}{"name": []string{"jinzhu""jinzhu 2"}}).Find(&users)
6// SELECT * FROM users WHERE name NOT IN ("jinzhu", "jinzhu 2");
7
8// Struct
9db.Not(User{Name: "jinzhu", Age: 18}).First(&user)
10// SELECT * FROM users WHERE name <> "jinzhu" AND age <> 18 ORDER BY id LIMIT 1;
11
12// 不在主键切片中的记录
13db.Not([]int64{1,2,3}).First(&user)
14// SELECT * FROM users WHERE id NOT IN (1,2,3) ORDER BY id LIMIT 1;

Or 条件

 1db.Where("role = ?""admin").Or("role = ?""super_admin").Find(&users)
2// SELECT * FROM users WHERE role = 'admin' OR role = 'super_admin';
3
4// Struct
5db.Where("name = 'jinzhu'").Or(User{Name: "jinzhu 2", Age: 18}).Find(&users)
6// SELECT * FROM users WHERE name = 'jinzhu' OR (name = 'jinzhu 2' AND age = 18);
7
8// Map
9db.Where("name = 'jinzhu'").Or(map[string]interface{}{"name""jinzhu 2""age"18}).Find(&users)
10// SELECT * FROM users WHERE name = 'jinzhu' OR (name = 'jinzhu 2' AND age = 18);

您还可以查看高级查询中的 分组条件,它被用于编写复杂 SQL

选择特定字段

选择您想从数据库中检索的字段,默认情况下会选择全部字段

1db.Select("name""age").Find(&users)
2// SELECT name, age FROM users;
3
4db.Select([]string{"name""age"}).Find(&users)
5// SELECT name, age FROM users;
6
7db.Table("users").Select("COALESCE(age,?)"42).Rows()
8// SELECT COALESCE(age,'42') FROM users;

还可以看一看 智能选择字段

Order

指定从数据库检索记录时的排序方式

 1db.Order("age desc, name").Find(&users)
2// SELECT * FROM users ORDER BY age desc, name;
3
4// 多个 order
5db.Order("age desc").Order("name").Find(&users)
6// SELECT * FROM users ORDER BY age desc, name;
7
8db.Clauses(clause.OrderBy{
9  Expression: clause.Expr{SQL: "FIELD(id,?)", Vars: []interface{}{[]int{123}}, WithoutParentheses: true},
10}).Find(&User{})
11// SELECT * FROM users ORDER BY FIELD(id,1,2,3)

Limit & Offset

Limit 指定获取记录的最大数量 Offset 指定在开始返回记录之前要跳过的记录数量

 1db.Limit(3).Find(&users)
2// SELECT * FROM users LIMIT 3;
3
4// 通过 -1 消除 Limit 条件
5db.Limit(10).Find(&users1).Limit(-1).Find(&users2)
6// SELECT * FROM users LIMIT 10; (users1)
7// SELECT * FROM users; (users2)
8
9db.Offset(3).Find(&users)
10// SELECT * FROM users OFFSET 3;
11
12db.Limit(10).Offset(5).Find(&users)
13// SELECT * FROM users OFFSET 5 LIMIT 10;
14
15// 通过 -1 消除 Offset 条件
16db.Offset(10).Find(&users1).Offset(-1).Find(&users2)
17// SELECT * FROM users OFFSET 10; (users1)
18// SELECT * FROM users; (users2)

查看 Pagination 学习如何写一个分页器

Group & Having

 1type result struct {
2  Date  time.Time
3  Total int
4}
5
6db.Model(&User{}).Select("name, sum(age) as total").Where("name LIKE ?""group%").Group("name").First(&result)
7// SELECT name, sum(age) as total FROM `users` WHERE name LIKE "group%" GROUP BY `name`
8
9
10db.Model(&User{}).Select("name, sum(age) as total").Group("name").Having("name = ?""group").Find(&result)
11// SELECT name, sum(age) as total FROM `users` GROUP BY `name` HAVING name = "group"
12
13rows, err := db.Table("orders").Select("date(created_at) as date, sum(amount) as total").Group("date(created_at)").Rows()
14for rows.Next() {
15  ...
16}
17
18rows, err := db.Table("orders").Select("date(created_at) as date, sum(amount) as total").Group("date(created_at)").Having("sum(amount) > ?"100).Rows()
19for rows.Next() {
20  ...
21}
22
23type Result struct {
24  Date  time.Time
25  Total int64
26}
27db.Table("orders").Select("date(created_at) as date, sum(amount) as total").Group("date(created_at)").Having("sum(amount) > ?"100).Scan(&results)

Distinct

从模型中选择不相同的值

1db.Distinct("name""age").Order("name, age desc").Find(&results)

Distinct 也可以配合 PluckCount 使用

Joins

指定 Joins 条件

 1type result struct {
2  Name  string
3  Email string
4}
5db.Model(&User{}).Select("users.name, emails.email").Joins("left join emails on emails.user_id = users.id").Scan(&result{})
6// SELECT users.name, emails.email FROM `users` left join emails on emails.user_id = users.id
7
8rows, err := db.Table("users").Select("users.name, emails.email").Joins("left join emails on emails.user_id = users.id").Rows()
9for rows.Next() {
10  ...
11}
12
13db.Table("users").Select("users.name, emails.email").Joins("left join emails on emails.user_id = users.id").Scan(&results)
14
15// 带参数的多表连接
16db.Joins("JOIN emails ON emails.user_id = users.id AND emails.email = ?""jinzhu@example.org").Joins("JOIN credit_cards ON credit_cards.user_id = users.id").Where("credit_cards.number = ?""411111111111").Find(&user)

Joins 预加载

您可以使用 Joins 实现单条 SQL 预加载关联记录,例如:

1db.Joins("Company").Find(&users)
2// SELECT `users`.`id`,`users`.`name`,`users`.`age`,`Company`.`id` AS `Company__id`,`Company`.`name` AS `Company__name` FROM `users` LEFT JOIN `companies` AS `Company` ON `users`.`company_id` = `Company`.`id`;

Scan

Scan 结果至 struct,用法与 Find 类似

 1type Result struct {
2  Name string
3  Age  int
4}
5
6var result Result
7db.Table("users").Select("name""age").Where("name = ?""Antonio").Scan(&result)
8
9// 原生 SQL
10db.Raw("SELECT name, age FROM users WHERE name = ?""Antonio").Scan(&result)

处理错误

GORM 的错误处理与常见的 Go 代码不同,因为 GORM 提供的是链式 API。

如果遇到任何错误,GORM 会设置 *gorm.DB 的 Error 字段,您需要像这样检查它:

1if err := db.Where("name = ?""jinzhu").First(&user).Error; err != nil {
2  // 处理错误...
3}

或者

1if result := db.Where("name = ?""jinzhu").First(&user); result.Error != nil {
2  // 处理错误...
3}

ErrRecordNotFound

当 FirstLastTake 方法找不到记录时,GORM 会返回 ErrRecordNotFound 错误。如果发生了多个错误,你可以通过 errors.Is 判断错误是否为 ErrRecordNotFound,例如:

1// 检查错误是否为 RecordNotFound
2err := db.First(&user, 100).Error
3errors.Is(err, gorm.ErrRecordNotFound)

技术是开放的,我们的心态,更应是开放的。拥抱变化,向阳而生,努力向前行。

更多高级用法和细节 可以查看 中文GROM网站,分享技术,分享快乐