3

gorm框架创建与查询

 2 years ago
source link: http://eryajf.net/pages/1243ce/#_10-%E6%89%AB%E6%8F%8F
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

# 1,创建

# 1,创建记录

首先定义模型:

type User struct {
    ID           int64
    Name         string
    Age          int64
}
1
2
3
4
5

使用使用NewRecord()查询主键是否存在,主键为空使用Create()创建记录:

u := User{Name: "eryajf", Age: 20} //结构体的初始化,相当于创建了一条用户数据

fmt.Println(db.NewRecord(&u))      //判断主键是否为空 true
db.Create(&u)                      //将上边定义的用户数据写入到数据库user表中
fmt.Println(db.NewRecord(&u))      //判断主键是否为空 false
1
2
3
4
5

# 2,默认值

可以通过 tag 定义字段的默认值,比如:

type User struct {
    ID   int64
    Name sql.NullString `gorm:"default:'eryajf'"`
    Age  int64
}
1
2
3
4
5

**注意:**通过tag定义字段的默认值,在创建记录时候生成的 SQL 语句会排除没有值或值为 零值 的字段。 在将记录插入到数据库后,Gorm会从数据库加载那些字段的默认值。

举个例子:

var user = User{Name: "", Age: 99}
db.Create(&user)

上面代码实际执行的SQL语句是INSERT INTO users("age") values('99');,排除了零值字段Name,而在数据库中这一条数据会使用设置的默认值eryajf作为Name字段的值。

**注意:**所有字段的零值, 比如0, "",false或者其它零值,都不会保存到数据库内,但会使用他们的默认值。 如果你想避免这种情况,可以考虑使用指针或实现 Scanner/Valuer接口

# 1,使用指针方式实现零值存入数据库

package main

import (
    "fmt"
    "github.com/jinzhu/gorm"
    _ "github.com/jinzhu/gorm/dialects/mysql"
)

// 定义模型
type User struct {
    ID   int64
    Name *string `gorm:"default:'eryajf'"`
    Age  int64
}

func main() {
    db, err := gorm.Open("mysql", "root:root1234@(127.0.0.1:13306)/db1?charset=utf8mb4&parseTime=True&loc=Local")
    if err != nil {
        panic(err)
    }
    defer db.Close()
    // 默认情况下,gorm创建的表将会是结构体名称的复数形式,如果不想让它自动复数,可以加一下禁用
    db.SingularTable(true)

    // 2, 把模型与数据库中的表对应起来
    db.AutoMigrate(&User{})

    u4 := User{Age: 24, Name: new(string)}
    fmt.Println(db.NewRecord(&u4))
    db.Debug().Create(&u4) // INSERT INTO `user` (`name`,`age`) VALUES ('',24)
    fmt.Println(db.NewRecord(&u4))
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

# 2,使用Scanner/Valuer接口方式实现零值存入数据库

package main

import (
    "database/sql"
    "fmt"
    "github.com/jinzhu/gorm"
    _ "github.com/jinzhu/gorm/dialects/mysql"
)

// 定义模型
type User struct {
    ID   int64
    Name sql.NullString `gorm:"default:'eryajf'"`
    Age  int64
}

func main() {
    db, err := gorm.Open("mysql", "root:root1234@(127.0.0.1:13306)/db1?charset=utf8mb4&parseTime=True&loc=Local")
    if err != nil {
        panic(err)
    }
    defer db.Close()
    // 默认情况下,gorm创建的表将会是结构体名称的复数形式,如果不想让它自动复数,可以加一下禁用
    db.SingularTable(true)

    // 2, 把模型与数据库中的表对应起来
    db.AutoMigrate(&User{})

    u4 := User{Age: 24, Name: sql.NullString{String: "", Valid: true}}
    fmt.Println(db.NewRecord(&u4))
    db.Debug().Create(&u4) // INSERT INTO `user` (`name`,`age`) VALUES ('',24)
    fmt.Println(db.NewRecord(&u4))
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33

# 3,扩展创建选项

例如PostgreSQL数据库中可以使用下面的方式实现合并插入, 有则更新, 无则插入。

// 为Instert语句添加扩展SQL选项
db.Set("gorm:insert_option", "ON CONFLICT").Create(&product)
// INSERT INTO products (name, code) VALUES ("name", "code") ON CONFLICT;

# 2,查询

# 1,普通查询

package main

import (
    "fmt"
    "github.com/jinzhu/gorm"
    _ "github.com/jinzhu/gorm/dialects/mysql"
)

// 定义模型
type User struct {
    gorm.Model
    Name string
    Age  int64
}

func main() {
    db, err := gorm.Open("mysql", "root:root1234@(127.0.0.1:13306)/db1?charset=utf8mb4&parseTime=True&loc=Local")
    if err != nil {
        panic(err)
    }
    defer db.Close()
    // 默认情况下,gorm创建的表将会是结构体名称的复数形式,如果不想让它自动复数,可以加一下禁用
    db.SingularTable(true)
    // 2, 把模型与数据库中的表对应起来
    db.AutoMigrate(&User{})
    // 3, 创建
    //u1 := User{Name: "eryajf", Age: 20}
    //db.Create(&u1)
    //u2 := User{Name: "jinzhu", Age: 22}
    //db.Create(&u2)

    // 4,查询
    var user []User
    db.Debug().First(&user) // SELECT * FROM `user`  WHERE `user`.`deleted_at` IS NULL ORDER BY `user`.`id` ASC LIMIT 1
    fmt.Println("根据主键查询第一条记录:", user)

    db.Debug().Take(&user) //SELECT * FROM `user`  WHERE `user`.`deleted_at` IS NULL LIMIT 1
    fmt.Println("随机获取一条记录:", user)

    db.Debug().Last(&user) //SELECT * FROM `user`  WHERE `user`.`deleted_at` IS NULL ORDER BY `user`.`id` DESC LIMIT 1
    fmt.Println("根据主键查询最后一条记录:", user)

    db.Debug().Find(&user) //SELECT * FROM `user`  WHERE `user`.`deleted_at` IS NULL
    fmt.Println("查询所有的记录:", user)

    db.Debug().First(&user, 2)      //SELECT * FROM `user`  WHERE `user`.`deleted_at` IS NULL AND ((`user`.`id` = 2)) ORDER BY `user`.`id` ASC LIMIT 1
    fmt.Println("查询指定的某条记录:", user) //仅当主键为整型时可用

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49

# 2,Where 条件

# 2,普通SQL查询

package main

import (
    "fmt"
    "github.com/jinzhu/gorm"
    _ "github.com/jinzhu/gorm/dialects/mysql"
    "time"
)

// 定义模型
type User struct {
    gorm.Model
    Name string
    Age  int64
}

func main() {
    db, err := gorm.Open("mysql", "root:root1234@(127.0.0.1:13306)/db1?charset=utf8mb4&parseTime=True&loc=Local")
    if err != nil {
        panic(err)
    }
    defer db.Close()
    // 默认情况下,gorm创建的表将会是结构体名称的复数形式,如果不想让它自动复数,可以加一下禁用
    db.SingularTable(true)
    // 2, 把模型与数据库中的表对应起来
    db.AutoMigrate(&User{})
    // 3, 创建
    //u1 := User{Name: "eryajf", Age: 20}
    //db.Create(&u1)
    //u2 := User{Name: "jinzhu", Age: 22}
    //db.Create(&u2)

    // 4,查询 // Where
    var user []User
    db.Debug().Where("name = ?", "jinzhu").First(&user) //SELECT * FROM `user`  WHERE `user`.`deleted_at` IS NULL AND ((name = 'jinzhu')) ORDER BY `user`.`id` ASC LIMIT 1
    fmt.Println("查询第一条匹配条件记录:", user)

    db.Debug().Where("name = ?", "jinzhu").Find(&user) //SELECT * FROM `user`  WHERE `user`.`deleted_at` IS NULL AND ((name = 'jinzhu'))
    fmt.Println("查询所有匹配条件的记录:", user)

    db.Debug().Where("name <> ?", "jinzhu").Find(&user) //SELECT * FROM `user`  WHERE `user`.`deleted_at` IS NULL AND ((name <> 'jinzhu'))
    fmt.Println("查询name不等于jinzhu的所有记录:", user)

    db.Debug().Where("name IN (?)", []string{"jinzhu", "jinzhu 2"}).Find(&user) //SELECT * FROM `user`  WHERE `user`.`deleted_at` IS NULL AND ((name IN ('jinzhu','jinzhu 2')))
    fmt.Println("查询name在jinzhu和jinzhu 2的所有记录:", user)

    db.Debug().Where("name LIKE ?", "%jin%").Find(&user) //SELECT * FROM `user`  WHERE `user`.`deleted_at` IS NULL AND ((name LIKE '%jin%'))
    fmt.Println("查询name包含jin的所有记录:", user)

    db.Debug().Where("name = ? AND age >= ?", "jinzhu", "20").Find(&user) //SELECT * FROM `user`  WHERE `user`.`deleted_at` IS NULL AND ((name = 'jinzhu' AND age >= '20'))
    fmt.Println("查询两个条件都符合的所有记录:", user)

    oneDay, _ := time.ParseDuration("-24h")
    lastWeek := time.Now().Add(oneDay * 7)
    db.Debug().Where("updated_at > ?", lastWeek).Find(&user) //SELECT * FROM `user`  WHERE `user`.`deleted_at` IS NULL AND ((updated_at > '2020-03-01 19:45:11'))
    fmt.Println("查询一周内更新的用户记录:", user)

    today := time.Now()
    db.Debug().Where("created_at BETWEEN ? AND ?", lastWeek, today).Find(&user) //SELECT * FROM `user`  WHERE `user`.`deleted_at` IS NULL AND ((created_at BETWEEN '2020-03-01 19:52:51' AND '2020-03-08 19:52:51'))
    fmt.Println("查询一周内创建的记录:", user)

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62

# 2,Struct & Map查询

package main

import (
    "fmt"
    "github.com/jinzhu/gorm"
    _ "github.com/jinzhu/gorm/dialects/mysql"
)

// 定义模型
type User struct {
    gorm.Model
    Name string
    Age  int64
}

func main() {
    db, err := gorm.Open("mysql", "root:root1234@(127.0.0.1:13306)/db1?charset=utf8mb4&parseTime=True&loc=Local")
    if err != nil {
        panic(err)
    }
    defer db.Close()
    // 默认情况下,gorm创建的表将会是结构体名称的复数形式,如果不想让它自动复数,可以加一下禁用
    db.SingularTable(true)
    // 2, 把模型与数据库中的表对应起来
    db.AutoMigrate(&User{})
    // 3, 创建
    //u1 := User{Name: "eryajf", Age: 20}
    //db.Create(&u1)
    //u2 := User{Name: "jinzhu", Age: 22}
    //db.Create(&u2)

    // 4,查询
    var user []User
    db.Debug().Where(&User{Name: "jinzhu", Age: 22}).First(&user) //SELECT * FROM `user`  WHERE `user`.`deleted_at` IS NULL AND ((`user`.`name` = 'jinzhu') AND (`user`.`age` = 22)) ORDER BY `user`.`id` ASC LIMIT 1
    fmt.Println("通过结构体查询:", user)

    db.Debug().Where(map[string]interface{}{"name": "jinzhu", "age": 22}).Find(&user) //SELECT * FROM `user`  WHERE `user`.`deleted_at` IS NULL AND ((`user`.`name` = 'jinzhu') AND (`user`.`age` = 22))
    fmt.Println("通过map查询:", user)

    db.Debug().Where([]int64{1, 2}).Find(&user) //SELECT * FROM `user`  WHERE `user`.`deleted_at` IS NULL AND ((`user`.`id` IN (1,2)))
    fmt.Println("通过主键的切片查询:", user)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42

**提示:**当通过结构体进行查询时,GORM将会只通过非零值字段查询,这意味着如果你的字段值为0''false或者其他零值时,将不会被用于构建查询条件,例如:

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

此时,就像创建一样,你可以使用指针或实现 Scanner/Valuer 接口来避免这个问题.

// 使用指针
type User struct {
  gorm.Model
  Name string
  Age  *int
}

// 使用 Scanner/Valuer
type User struct {
  gorm.Model
  Name string
  Age  sql.NullInt64  // sql.NullInt64 实现了 Scanner/Valuer 接口
}
1
2
3
4
5
6
7
8
9
10
11
12
13

# 3,Not 条件

作用与 Where 类似的情形如下:

package main

import (
    "fmt"
    "github.com/jinzhu/gorm"
    _ "github.com/jinzhu/gorm/dialects/mysql"
)

// 定义模型
type User struct {
    gorm.Model
    Name string
    Age  int64
}

func main() {
    db, err := gorm.Open("mysql", "root:root1234@(127.0.0.1:13306)/db1?charset=utf8mb4&parseTime=True&loc=Local")
    if err != nil {
        panic(err)
    }
    defer db.Close()
    // 默认情况下,gorm创建的表将会是结构体名称的复数形式,如果不想让它自动复数,可以加一下禁用
    db.SingularTable(true)
    // 2, 把模型与数据库中的表对应起来
    db.AutoMigrate(&User{})
    // 3, 创建
    //u1 := User{Name: "eryajf", Age: 20}
    //db.Create(&u1)
    //u2 := User{Name: "jinzhu", Age: 22}
    //db.Create(&u2)

    // 4,查询
    var user []User

    db.Debug().Not("name", "jinzhu").First(&user) //SELECT * FROM `user`  WHERE `user`.`deleted_at` IS NULL AND ((`user`.`name` NOT IN ('jinzhu'))) ORDER BY `user`.`id` ASC LIMIT 1
    fmt.Println("查询name不是jinzhu的第一条记录:", user)

    db.Debug().Not("name", []string{"jinzhu", "jinzhu 2"}).Find(&user) //SELECT * FROM `user`  WHERE `user`.`deleted_at` IS NULL AND ((`user`.`name` NOT IN ('jinzhu','jinzhu 2')))
    fmt.Println("查询name不在jinzhu或jinzhu2的所有记录:", user)

    db.Debug().Not([]int64{1, 2, 3}).Find(&user) //SELECT * FROM `user`  WHERE `user`.`deleted_at` IS NULL AND ((`user`.`id` NOT IN (1,2,3)))
    fmt.Println("查询主键不是1,2,3的所有记录:", user)

    db.Debug().Not([]int64{}).First(&user) //SELECT * FROM `user`  WHERE `user`.`deleted_at` IS NULL ORDER BY `user`.`id` ASC LIMIT 1
    fmt.Println("查询所有用户中的第一个:", user)

    db.Debug().Not("name = ?", "jinzhu").First(&user) //SELECT * FROM `user`  WHERE `user`.`deleted_at` IS NULL AND (NOT (name = 'jinzhu')) ORDER BY `user`.`id` ASC LIMIT 1
    fmt.Println("查询name不是jinzhu的第一个用户:", user)

    db.Debug().Not(User{Name: "jinzhu"}).First(&user) //SELECT * FROM `user`  WHERE `user`.`deleted_at` IS NULL AND ((`user`.`name` <> 'jinzhu')) ORDER BY `user`.`id` ASC LIMIT 1
    fmt.Println("通过结构体查询name不是jinzhu的第一个用户:", user)

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53

# 4,Or条件

package main

import (
    "fmt"
    "github.com/jinzhu/gorm"
    _ "github.com/jinzhu/gorm/dialects/mysql"
)

// 定义模型
type User struct {
    gorm.Model
    Name string
    Age  int64
}

func main() {
    db, err := gorm.Open("mysql", "root:root1234@(127.0.0.1:13306)/db1?charset=utf8mb4&parseTime=True&loc=Local")
    if err != nil {
        panic(err)
    }
    defer db.Close()
    // 默认情况下,gorm创建的表将会是结构体名称的复数形式,如果不想让它自动复数,可以加一下禁用
    db.SingularTable(true)
    // 2, 把模型与数据库中的表对应起来
    db.AutoMigrate(&User{})
    // 3, 创建
    //u1 := User{Name: "eryajf", Age: 20}
    //db.Create(&u1)
    //u2 := User{Name: "jinzhu", Age: 22}
    //db.Create(&u2)

    // 4,查询
    var user []User

    db.Debug().Where("age > ?", 25).Or("age < ?", 23).Find(&user) //SELECT * FROM `user`  WHERE `user`.`deleted_at` IS NULL AND ((age > 25) OR (age < 23))
    fmt.Println("查询年龄小于23的或者大于25的所有记录:", user)

    // struct
    db.Debug().Where("name = 'jinzhu'").Or(User{Name: "jinzhu 2"}).Find(&user) //SELECT * FROM `user`  WHERE `user`.`deleted_at` IS NULL AND ((name = 'jinzhu') OR (`user`.`name` = 'jinzhu 2'))
    fmt.Println("结构体:查询名字是jinzhu的或者是jinzhu 2的所有记录:", user)

    // map
    db.Debug().Where("name = 'jinzhu'").Or(map[string]interface{}{"name": "jinzhu 2"}).Find(&user) //SELECT * FROM `user`  WHERE `user`.`deleted_at` IS NULL AND ((name = 'jinzhu') OR (`user`.`name` = 'jinzhu 2'))
    fmt.Println("map:查询名字是jinzhu的或者是jinzhu 2的所有记录:", user)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45

# 5,内联条件

作用与Where查询类似,当内联条件与多个立即执行方法 (opens new window)一起使用时, 内联条件不会传递给后面的立即执行方法。

package main

import (
    "fmt"
    "github.com/jinzhu/gorm"
    _ "github.com/jinzhu/gorm/dialects/mysql"
)

// 定义模型
type User struct {
    gorm.Model
    Name string
    Age  int64
}

func main() {
    db, err := gorm.Open("mysql", "root:root1234@(127.0.0.1:13306)/db1?charset=utf8mb4&parseTime=True&loc=Local")
    if err != nil {
        panic(err)
    }
    defer db.Close()
    // 默认情况下,gorm创建的表将会是结构体名称的复数形式,如果不想让它自动复数,可以加一下禁用
    db.SingularTable(true)
    // 2, 把模型与数据库中的表对应起来
    db.AutoMigrate(&User{})
    // 3, 创建
    //u1 := User{Name: "eryajf", Age: 20}
    //db.Create(&u1)
    //u2 := User{Name: "jinzhu", Age: 22}
    //db.Create(&u2)

    // 4,查询
    var user []User

    db.Debug().First(&user, 3)          //SELECT * FROM `user`  WHERE `user`.`deleted_at` IS NULL AND ((`user`.`id` = 3)) ORDER BY `user`.`id` ASC LIMIT 1
    fmt.Println("根据主键查询指定的某条记录:", user) //仅当主键为整型时可用

    db.Debug().First(&user, "id = ?", "string_primary_key") //SELECT * FROM `user`  WHERE `user`.`deleted_at` IS NULL AND ((id = 'string_primary_key')) ORDER BY `user`.`id` ASC LIMIT 1
    fmt.Println("根据主键是非整形主键获取记录:", user)

    db.Debug().Find(&user, "name = ?", "jinzhu") //SELECT * FROM `user`  WHERE `user`.`deleted_at` IS NULL AND ((name = 'jinzhu'))
    fmt.Println("查询name为jinzhu的记录:", user)

    db.Debug().Find(&user, "name <> ? AND age > ? ", "jinzhu", "20") //SELECT * FROM `user`  WHERE `user`.`deleted_at` IS NULL AND ((name <> 'jinzhu' AND age > '20' ))
    fmt.Println("查询name不是jinzhu且年龄大于20的记录:", user)

    db.Debug().Find(&user, User{Age: 20}) //SELECT * FROM `user`  WHERE `user`.`deleted_at` IS NULL AND ((`user`.`age` = 20))
    fmt.Println("通过结构体查询年龄是20的所有记录:", user)

    db.Debug().Find(&user, map[string]interface{}{"age": 20}) //SELECT * FROM `user`  WHERE `user`.`deleted_at` IS NULL AND ((`user`.`age` = 20))
    fmt.Println("通过map查询年龄是20的所有记录:", user)

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53

# 6,额外查询选项

// 为查询 SQL 添加额外的 SQL 操作
db.Set("gorm:query_option", "FOR UPDATE").First(&user, 10)
//// SELECT * FROM users WHERE id = 10 FOR UPDATE;

# 7,FirstOrInit

获取匹配的第一条记录,否则根据给定的条件初始化一个新的对象 (仅支持 struct 和 map 条件)

package main

import (
    "fmt"
    "github.com/jinzhu/gorm"
    _ "github.com/jinzhu/gorm/dialects/mysql"
)

// 定义模型
type User struct {
    gorm.Model
    Name string
    Age  int64
}

func main() {
    db, err := gorm.Open("mysql", "root:root1234@(127.0.0.1:13306)/db1?charset=utf8mb4&parseTime=True&loc=Local")
    if err != nil {
        panic(err)
    }
    defer db.Close()
    // 默认情况下,gorm创建的表将会是结构体名称的复数形式,如果不想让它自动复数,可以加一下禁用
    db.SingularTable(true)
    // 2, 把模型与数据库中的表对应起来
    db.AutoMigrate(&User{})
    // 3, 创建
    //u1 := User{Name: "eryajf", Age: 20}
    //db.Create(&u1)
    //u2 := User{Name: "jinzhu", Age: 22}
    //db.Create(&u2)

    // 4,查询
    var user []User

    db.Debug().FirstOrInit(&user, User{Name: "non_existing"}) //SELECT * FROM `user`  WHERE `user`.`deleted_at` IS NULL AND ((`user`.`name` = 'non_existing')) ORDER BY `user`.`id` ASC LIMIT 1
    fmt.Println("查询name为non_existing的记录:", user)

    db.Debug().Where(User{Name: "jinzhu"}).FirstOrInit(&user) //SELECT * FROM `user`  WHERE `user`.`deleted_at` IS NULL AND ((`user`.`name` = 'jinzhu')) ORDER BY `user`.`id` ASC LIMIT 1
    fmt.Println("通过结构体查询name为jinzhu的记录:", user)

    db.Debug().FirstOrInit(&user, map[string]interface{}{"name": "jinzhu"}) //SELECT * FROM `user`  WHERE `user`.`deleted_at` IS NULL AND ((`user`.`name` = 'jinzhu')) ORDER BY `user`.`id` ASC LIMIT 1
    fmt.Println("通过map查询name为jinzhu的记录:", user)

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44

# 1,Attrs

如果记录未找到,将使用参数初始化 struct.

package main

import (
    "fmt"
    "github.com/jinzhu/gorm"
    _ "github.com/jinzhu/gorm/dialects/mysql"
)

// 定义模型
type User struct {
    gorm.Model
    Name string
    Age  int64
}

func main() {
    db, err := gorm.Open("mysql", "root:root1234@(127.0.0.1:13306)/db1?charset=utf8mb4&parseTime=True&loc=Local")
    if err != nil {
        panic(err)
    }
    defer db.Close()
    // 默认情况下,gorm创建的表将会是结构体名称的复数形式,如果不想让它自动复数,可以加一下禁用
    db.SingularTable(true)
    // 2, 把模型与数据库中的表对应起来
    db.AutoMigrate(&User{})
    // 3, 创建
    //u1 := User{Name: "eryajf", Age: 20}
    //db.Create(&u1)
    //u2 := User{Name: "jinzhu", Age: 22}
    //db.Create(&u2)

    // 4,查询
    var user []User

    // 未找到
    db.Debug().Where(User{Name: "non_existing"}).Attrs(User{Age: 20}).FirstOrInit(&user) //SELECT * FROM `user`  WHERE `user`.`deleted_at` IS NULL AND ((`user`.`name` = 'non_existing')) ORDER BY `user`.`id` ASC LIMIT 1
    fmt.Println(user)

    db.Debug().Where(User{Name: "non_existing"}).Attrs("age", 20).FirstOrInit(&user) //SELECT * FROM `user`  WHERE `user`.`deleted_at` IS NULL AND ((`user`.`name` = 'non_existing')) ORDER BY `user`.`id` ASC LIMIT 1
    fmt.Println(user)

    // 找到
    db.Debug().Where(User{Name: "jinzhu"}).Attrs(User{Age: 50}).FirstOrInit(&user) //SELECT * FROM `user`  WHERE `user`.`deleted_at` IS NULL AND ((`user`.`name` = 'jinzhu')) ORDER BY `user`.`id` ASC LIMIT 1
    fmt.Println(user)

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46

# 2,Assign

不管记录是否找到,都将参数赋值给 struct.

package main

import (
    "fmt"
    "github.com/jinzhu/gorm"
    _ "github.com/jinzhu/gorm/dialects/mysql"
)

// 定义模型
type User struct {
    gorm.Model
    Name string
    Age  int64
}

func main() {
    db, err := gorm.Open("mysql", "root:root1234@(127.0.0.1:13306)/db1?charset=utf8mb4&parseTime=True&loc=Local")
    if err != nil {
        panic(err)
    }
    defer db.Close()
    // 默认情况下,gorm创建的表将会是结构体名称的复数形式,如果不想让它自动复数,可以加一下禁用
    db.SingularTable(true)
    // 2, 把模型与数据库中的表对应起来
    db.AutoMigrate(&User{})
    // 3, 创建
    //u1 := User{Name: "eryajf", Age: 20}
    //db.Create(&u1)
    //u2 := User{Name: "jinzhu", Age: 22}
    //db.Create(&u2)

    // 4,查询
    var user []User

    db.Debug().Where(User{Name: "non_existing"}).Assign(User{Age: 20}).FirstOrInit(&user) //SELECT * FROM `user`  WHERE `user`.`deleted_at` IS NULL AND ((`user`.`name` = 'non_existing')) ORDER BY `user`.`id` ASC LIMIT 1
    fmt.Println(user)

    // 找到
    db.Debug().Where(User{Name: "jinzhu"}).Assign(User{Age: 50}).FirstOrInit(&user) //SELECT * FROM `user`  WHERE `user`.`deleted_at` IS NULL AND ((`user`.`name` = 'jinzhu')) ORDER BY `user`.`id` ASC LIMIT 1
    fmt.Println(user)

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42

# 8,FirstOrCreate

获取匹配的第一条记录, 否则根据给定的条件创建一个新的记录 (仅支持 struct 和 map 条件)

package main

import (
    "fmt"
    "github.com/jinzhu/gorm"
    _ "github.com/jinzhu/gorm/dialects/mysql"
)

// 定义模型
type User struct {
    gorm.Model
    Name string
    Age  int64
}

func main() {
    db, err := gorm.Open("mysql", "root:root1234@(127.0.0.1:13306)/db1?charset=utf8mb4&parseTime=True&loc=Local")
    if err != nil {
        panic(err)
    }
    defer db.Close()
    // 默认情况下,gorm创建的表将会是结构体名称的复数形式,如果不想让它自动复数,可以加一下禁用
    db.SingularTable(true)
    // 2, 把模型与数据库中的表对应起来
    db.AutoMigrate(&User{})
    // 3, 创建
    //u1 := User{Name: "eryajf", Age: 20}
    //db.Create(&u1)
    //u2 := User{Name: "jinzhu", Age: 22}
    //db.Create(&u2)

    // 4,查询
    var user []User

    db.Debug().FirstOrCreate(&user, User{Name: "non_existing"}) //SELECT * FROM `user`  WHERE `user`.`deleted_at` IS NULL AND ((`user`.`name` = 'non_existing')) ORDER BY `user`.`id` ASC LIMIT 1
    fmt.Println(user)

    db.Debug().Where(User{Name: "jinzhu"}).FirstOrCreate(&user) //SELECT * FROM `user`  WHERE `user`.`deleted_at` IS NULL AND ((`user`.`name` = 'jinzhu')) ORDER BY `user`.`id` ASC LIMIT 1
    fmt.Println(user)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40

# 1,Attrs

如果记录未找到,将使用参数创建 struct 和记录.

package main

import (
    "fmt"
    "github.com/jinzhu/gorm"
    _ "github.com/jinzhu/gorm/dialects/mysql"
)

// 定义模型
type User struct {
    gorm.Model
    Name string
    Age  int64
}

func main() {
    db, err := gorm.Open("mysql", "root:root1234@(127.0.0.1:13306)/db1?charset=utf8mb4&parseTime=True&loc=Local")
    if err != nil {
        panic(err)
    }
    defer db.Close()
    // 默认情况下,gorm创建的表将会是结构体名称的复数形式,如果不想让它自动复数,可以加一下禁用
    db.SingularTable(true)
    // 2, 把模型与数据库中的表对应起来
    db.AutoMigrate(&User{})
    // 3, 创建
    //u1 := User{Name: "eryajf", Age: 20}
    //db.Create(&u1)
    //u2 := User{Name: "jinzhu", Age: 22}
    //db.Create(&u2)

    // 4,查询
    var user []User

    db.Debug().Where(User{Name: "non_existing"}).Attrs(User{Age: 20}).FirstOrCreate(&user) //SELECT * FROM `user`  WHERE `user`.`deleted_at` IS NULL AND ((`user`.`name` = 'non_existing')) ORDER BY `user`.`id` ASC LIMIT 1
    fmt.Println(user)

    db.Debug().Where(User{Name: "jinzhu"}).Attrs(User{Age: 30}).FirstOrCreate(&user) //SELECT * FROM `user`  WHERE `user`.`deleted_at` IS NULL AND ((`user`.`name` = 'jinzhu')) ORDER BY `user`.`id` ASC LIMIT 1
    fmt.Println(user)
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41

# 2,Assign

不管记录是否找到,都将参数赋值给 struct 并保存至数据库.

// 未找到
db.Where(User{Name: "non_existing"}).Assign(User{Age: 20}).FirstOrCreate(&user)
//// SELECT * FROM users WHERE name = 'non_existing';
//// INSERT INTO "users" (name, age) VALUES ("non_existing", 20);
//// user -> User{Id: 112, Name: "non_existing", Age: 20}

// 找到
db.Where(User{Name: "jinzhu"}).Assign(User{Age: 30}).FirstOrCreate(&user)
//// SELECT * FROM users WHERE name = 'jinzhu';
//// UPDATE users SET age=30 WHERE id = 111;
//// user -> User{Id: 111, Name: "jinzhu", Age: 30}
1
2
3
4
5
6
7
8
9
10
11

# 9,高级查询

# 1,子查询

基于 *gorm.expr 的子查询

db.Where("amount > ?", DB.Table("orders").Select("AVG(amount)").Where("state = ?", "paid").QueryExpr()).Find(&orders)
// SELECT * FROM "orders"  WHERE "orders"."deleted_at" IS NULL AND (amount > (SELECT AVG(amount) FROM "orders"  WHERE (state = 'paid')));

# 2,选择字段

Select,指定你想从数据库中检索出的字段,默认会选择全部字段。

package main

import (
    "fmt"
    "github.com/jinzhu/gorm"
    _ "github.com/jinzhu/gorm/dialects/mysql"
)

// 定义模型
type User struct {
    gorm.Model
    Name string
    Age  int64
}

func main() {
    db, err := gorm.Open("mysql", "root:root1234@(127.0.0.1:13306)/db1?charset=utf8mb4&parseTime=True&loc=Local")
    if err != nil {
        panic(err)
    }
    defer db.Close()
    // 默认情况下,gorm创建的表将会是结构体名称的复数形式,如果不想让它自动复数,可以加一下禁用
    db.SingularTable(true)
    // 2, 把模型与数据库中的表对应起来
    db.AutoMigrate(&User{})
    // 3, 创建
    //u1 := User{Name: "eryajf", Age: 20}
    //db.Create(&u1)
    //u2 := User{Name: "jinzhu", Age: 22}
    //db.Create(&u2)

    // 4,查询
    var user []User

    db.Debug().Select("name", "age").Find(&user) //SELECT name FROM `user`  WHERE `user`.`deleted_at` IS NULL'age'
    fmt.Println("查询表中name字段参数为age的记录:", user)

    db.Debug().Select([]string{"name", "age"}).Find(&user) //SELECT name, age FROM `user`  WHERE `user`.`deleted_at` IS NULL
    fmt.Println("列出表中name与age字段:", user)

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41

# 3,排序

Order,指定从数据库中检索出记录的顺序。设置第二个参数 reorder 为 true ,可以覆盖前面定义的排序条件。

db.Order("age desc, name").Find(&users)
//// SELECT * FROM users ORDER BY age desc, name;

// 多字段排序
db.Order("age desc").Order("name").Find(&users)
//// SELECT * FROM users ORDER BY age desc, name;

// 覆盖排序
db.Order("age desc").Find(&users1).Order("age", true).Find(&users2)
//// SELECT * FROM users ORDER BY age desc; (users1)
//// SELECT * FROM users ORDER BY age; (users2)
1
2
3
4
5
6
7
8
9
10
11

# 4,数量

Limit,指定从数据库检索出的最大记录数。

db.Limit(3).Find(&users)
//// SELECT * FROM users LIMIT 3;

// -1 取消 Limit 条件
db.Limit(10).Find(&users1).Limit(-1).Find(&users2)
//// SELECT * FROM users LIMIT 10; (users1)
//// SELECT * FROM users; (users2)
1
2
3
4
5
6
7

# 5,偏移

Offset,指定开始返回记录前要跳过的记录数。

db.Offset(3).Find(&users)
//// SELECT * FROM users OFFSET 3;

// -1 取消 Offset 条件
db.Offset(10).Find(&users1).Offset(-1).Find(&users2)
//// SELECT * FROM users OFFSET 10; (users1)
//// SELECT * FROM users; (users2)
1
2
3
4
5
6
7

# 6,总数

Count,该 model 能获取的记录总数。

db.Where("name = ?", "jinzhu").Or("name = ?", "jinzhu 2").Find(&users).Count(&count)
//// SELECT * from USERS WHERE name = 'jinzhu' OR name = 'jinzhu 2'; (users)
//// SELECT count(*) FROM users WHERE name = 'jinzhu' OR name = 'jinzhu 2'; (count)

db.Model(&User{}).Where("name = ?", "jinzhu").Count(&count)
//// SELECT count(*) FROM users WHERE name = 'jinzhu'; (count)

db.Table("deleted_users").Count(&count)
//// SELECT count(*) FROM deleted_users;

db.Table("deleted_users").Select("count(distinct(name))").Count(&count)
//// SELECT count( distinct(name) ) FROM deleted_users; (count)
1
2
3
4
5
6
7
8
9
10
11
12

注意 Count 必须是链式查询的最后一个操作 ,因为它会覆盖前面的 SELECT,但如果里面使用了 count 时不会覆盖

# 7,Group & Having

rows, err := db.Table("orders").Select("date(created_at) as date, sum(amount) as total").Group("date(created_at)").Rows()
for rows.Next() {
  ...
}

// 使用Scan将多条结果扫描进事先准备好的结构体切片中
type Result struct {
    Date time.Time
    Total int
}
var rets []Result
db.Table("users").Select("date(created_at) as date, sum(age) as total").Group("date(created_at)").Scan(&rets)

rows, err := db.Table("orders").Select("date(created_at) as date, sum(amount) as total").Group("date(created_at)").Having("sum(amount) > ?", 100).Rows()
for rows.Next() {
  ...
}

type Result struct {
  Date  time.Time
  Total int64
}
db.Table("orders").Select("date(created_at) as date, sum(amount) as total").Group("date(created_at)").Having("sum(amount) > ?", 100).Scan(&results)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

# 8,连接

Joins,指定连接条件

rows, err := db.Table("users").Select("users.name, emails.email").Joins("left join emails on emails.user_id = users.id").Rows()
for rows.Next() {
  ...
}

db.Table("users").Select("users.name, emails.email").Joins("left join emails on emails.user_id = users.id").Scan(&results)

// 多连接及参数
db.Joins("JOIN emails ON emails.user_id = users.id AND emails.email = ?", "[email protected]").Joins("JOIN credit_cards ON credit_cards.user_id = users.id").Where("credit_cards.number = ?", "411111111111").Find(&user)
1
2
3
4
5
6
7
8
9

# 9,Pluck

Pluck,查询 model 中的一个列作为切片,如果您想要查询多个列,您应该使用 Scan (opens new window)

var ages []int64
db.Find(&users).Pluck("age", &ages)

var names []string
db.Model(&User{}).Pluck("name", &names)

db.Table("deleted_users").Pluck("name", &names)

// 想查询多个字段? 这样做:
db.Select("name, age").Find(&users)
1
2
3
4
5
6
7
8
9
10

# 10,扫描

Scan,扫描结果至一个 struct.

type Result struct {
  Name string
  Age  int
}

var result Result
db.Table("users").Select("name, age").Where("name = ?", "Antonio").Scan(&result)

var results []Result
db.Table("users").Select("name, age").Where("id > ?", 0).Scan(&results)

// 原生 SQL
db.Raw("SELECT name, age FROM users WHERE name = ?", "Antonio").Scan(&result)
1
2
3
4
5
6
7
8
9
10
11
12
13

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK