04.sqlx-In函数
  # 01.准备工作
# 1.1 表结构
CREATE TABLE `user` (
    `id` BIGINT(20) NOT NULL AUTO_INCREMENT,
    `name` VARCHAR(20) DEFAULT '',
    `age` INT(11) DEFAULT '0',
    PRIMARY KEY(`id`)
)ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4;
 1
2
3
4
5
6
2
3
4
5
6
# 1.2 结构体
- 定义一个
user结构体,字段通过tag与数据库中user表的列一致。 
type User struct {
	Name string `db:"name"`
	Age  int    `db:"age"`
}
 1
2
3
4
2
3
4
# 02.使用sqlx.In实现批量插入
# 2.1 自己拼接语句实现批量插入
- 比较笨,但是很好理解。就是有多少个User就拼接多少个
(?, ?)。 
package main
import (
	"fmt"
	_ "github.com/go-sql-driver/mysql"
	"github.com/jmoiron/sqlx"
	"strings"
)
// 第一:建立连接
var DB *sqlx.DB
func initDB() (err error) {
	dsn := "root:chnsys@2016@tcp(127.0.0.1:3306)/sql_demo?charset=utf8mb4&parseTime=True"
	// 也可以使用MustConnect连接不成功就panic
	DB, err = sqlx.Connect("mysql", dsn)
	if err != nil {
		fmt.Printf("connect DB failed, err:%v\n", err)
		return
	}
	DB.SetMaxOpenConns(2000)
	DB.SetMaxIdleConns(10)
	return
}
// 第二:定义结构体
type User struct {
	Name string `db:"name"`
	Age  int    `db:"age"`
}
// 第三:自行构造批量插入的语句
func BatchInsertUsers(users []*User) error {
	// 存放 (?, ?) 的slice
	valueStrings := make([]string, 0, len(users))
	// 存放values的slice
	valueArgs := make([]interface{}, 0, len(users) * 2)
	// 遍历users准备相关数据
	for _, u := range users {
		// 此处占位符要与插入值的个数对应
		valueStrings = append(valueStrings, "(?, ?)")
		valueArgs = append(valueArgs, u.Name)
		valueArgs = append(valueArgs, u.Age)
	}
	// 自行拼接要执行的具体语句
	stmt := fmt.Sprintf("INSERT INTO user (name, age) VALUES %s",
		strings.Join(valueStrings, ","))
	_, err := DB.Exec(stmt, valueArgs...)
	return err
}
// 第四:main函数调用
func main() {
	err := initDB()
	if err != nil {
		panic(err)
	}
	defer DB.Close()
	u1 := User{Name: "wangwu", Age: 18}
	u2 := User{Name: "zhaoliu", Age: 28}
	u3 := User{Name: "sunqi", Age: 38}
	// 方法1
	users := []*User{&u1, &u2, &u3}
	err = BatchInsertUsers(users)
	if err != nil {
		fmt.Printf("BatchInsertUsers failed, err:%v\n", err)
	}
}
 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
63
64
65
66
67
68
69
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
63
64
65
66
67
68
69
# 2.2 使用sqlx.In实现批量插入
package main
import (
	"database/sql/driver"
	"fmt"
	_ "github.com/go-sql-driver/mysql"
	"github.com/jmoiron/sqlx"
)
// 第一:建立数据库连接
var DB *sqlx.DB
func initDB() (err error) {
	dsn := "root:chnsys@2016@tcp(127.0.0.1:3306)/sql_demo?charset=utf8mb4&parseTime=True"
	// 也可以使用MustConnect连接不成功就panic
	DB, err = sqlx.Connect("mysql", dsn)
	if err != nil {
		fmt.Printf("connect DB failed, err:%v\n", err)
		return
	}
	DB.SetMaxOpenConns(2000)
	DB.SetMaxIdleConns(10)
	return
}
// 第二:定义结构体
type User struct {
	Name string `db:"name"`
	Age  int    `db:"age"`
}
// 第三:前提是需要我们的结构体实现driver.Valuer接口
// 前提是需要我们的结构体实现driver.Value 接口
func (u User) Value() (driver.Value, error) {
	return []interface{}{u.Name, u.Age}, nil
}
// 第四:使用sqlx.In实现批量插入代码如下
// 使用sqlx.In帮我们拼接语句和参数, 注意传入的参数是[]interface{}
func BatchInsertUsers2(users []interface{}) error {
	query, args, _ := sqlx.In(
		"INSERT INTO user (name, age) VALUES (?), (?), (?)",
		users..., // 如果arg实现了 driver.Valuer, sqlx.In 会通过调用 Value()来展开它
	)
	fmt.Println(query) // 查看生成的querystring
	fmt.Println(args)  // 查看生成的args
	_, err := DB.Exec(query, args...)
	return err
}
// 第五:mian函数调用
func main() {
	err := initDB()
	if err != nil {
		panic(err)
	}
	defer DB.Close()
	u1 := User{Name: "wangwu", Age: 18}
	u2 := User{Name: "zhaoliu", Age: 28}
	u3 := User{Name: "sunqi", Age: 38}
	// 方法2
	users2 := []interface{}{u1, u2, u3}
	err = BatchInsertUsers2(users2)
	if err != nil {
		fmt.Printf("BatchInsertUsers2 failed, err:%v\n", err)
	}
}
 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
63
64
65
66
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
63
64
65
66
# 2.3 使用NamedExec实现批量插入
推荐使用此方法注意 :该功能需1.3.1版本以上,并且1.3.1版本目前还有点问题,sql语句最后不能有空格和
;,详见issues/690 (opens new window)。
package main
import (
	"fmt"
	_ "github.com/go-sql-driver/mysql"
	"github.com/jmoiron/sqlx"
)
// 第一:建立数据库连接
var DB *sqlx.DB
func initDB() (err error) {
	dsn := "root:chnsys@2016@tcp(127.0.0.1:3306)/sql_demo?charset=utf8mb4&parseTime=True"
	// 也可以使用MustConnect连接不成功就panic
	DB, err = sqlx.Connect("mysql", dsn)
	if err != nil {
		fmt.Printf("connect DB failed, err:%v\n", err)
		return
	}
	DB.SetMaxOpenConns(2000)
	DB.SetMaxIdleConns(10)
	return
}
// 第二:定义结构体
type User struct {
	Name string `db:"name"`
	Age  int    `db:"age"`
}
// 第三:使用NamedExec实现批量插入
func BatchInsertUsers3(users []*User) error {
	_, err := DB.NamedExec("INSERT INTO user (name, age) VALUES (:name, :age)", users)
	return err
}
// 第四:mian函数调用
func main() {
	err := initDB()
	if err != nil {
		panic(err)
	}
	defer DB.Close()
	u1 := User{Name: "wangwu", Age: 18}
	u2 := User{Name: "zhaoliu", Age: 28}
	u3 := User{Name: "sunqi", Age: 38}
	// 方法3
	users3 := []*User{&u1, &u2, &u3}
	err = BatchInsertUsers3(users3)
	if err != nil {
		fmt.Printf("BatchInsertUsers3 failed, err:%v\n", err)
	}
}
 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
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
# 03.使用sqlx.In实现查询
# 3.1 sqlx.In的查询示例
- 关于
sqlx.In这里再补充一个用法,在sqlx查询语句中实现In查询和FIND_IN_SET函数。 - 即实现
SELECT * FROM user WHERE id in (3, 2, 1); - 和
SELECT * FROM user WHERE id in (3, 2, 1) ORDER BY FIND_IN_SET(id, '3,2,1'); 
# 3.2 in查询
- 查询id在给定id集合中的数据
 
package main
import (
	"fmt"
	_ "github.com/go-sql-driver/mysql"
	"github.com/jmoiron/sqlx"
)
// 第一:建立数据库连接
var DB *sqlx.DB
func initDB() (err error) {
	dsn := "root:chnsys@2016@tcp(127.0.0.1:3306)/sql_demo?charset=utf8mb4&parseTime=True"
	// 也可以使用MustConnect连接不成功就panic
	DB, err = sqlx.Connect("mysql", dsn)
	if err != nil {
		fmt.Printf("connect DB failed, err:%v\n", err)
		return
	}
	DB.SetMaxOpenConns(2000)
	DB.SetMaxIdleConns(10)
	return
}
// 第二:定义结构体
type User struct {
	Name string `db:"name"`
	Age  int    `db:"age"`
}
// 第三:QueryByIDs 根据给定ID查询
func QueryByIDs(ids []int)(users []User, err error){
	// 动态填充id
	query, args, err := sqlx.In("SELECT name, age FROM user WHERE id IN (?)", ids)
	if err != nil {
		return
	}
	// sqlx.In 返回带 `?` bindvar的查询语句, 我们使用Rebind()重新绑定它
	query = DB.Rebind(query)
	err = DB.Select(&users, query, args...)
	return
}
// 第四:mian函数调用
func main() {
	err := initDB()
	if err != nil {
		panic(err)
	}
	defer DB.Close()
	users , err := QueryByIDs([]int{7,5,6, 1})
	if err != nil {
		fmt.Printf("QueryByIDs failed, err:%v\n", err)
		return
	}
	for _, user := range users{
		fmt.Printf("user:%#v\n", user)
	}
}
/*
user:main.User{Name:"沙河小王子", Age:20}
user:main.User{Name:"zhaoliu", Age:28}
user:main.User{Name:"sunqi", Age:38}
user:main.User{Name:"wangwu", Age:18}
 */
 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
63
64
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
63
64
# 3.3 in查询和FIND_IN_SET函数
package main
import (
	"fmt"
	_ "github.com/go-sql-driver/mysql"
	"github.com/jmoiron/sqlx"
	"strings"
)
// 第一:建立数据库连接
var DB *sqlx.DB
func initDB() (err error) {
	dsn := "root:chnsys@2016@tcp(127.0.0.1:3306)/sql_demo?charset=utf8mb4&parseTime=True"
	// 也可以使用MustConnect连接不成功就panic
	DB, err = sqlx.Connect("mysql", dsn)
	if err != nil {
		fmt.Printf("connect DB failed, err:%v\n", err)
		return
	}
	DB.SetMaxOpenConns(2000)
	DB.SetMaxIdleConns(10)
	return
}
// 第二:定义结构体
type User struct {
	Name string `db:"name"`
	Age  int    `db:"age"`
}
// 第三:QueryAndOrderByIDs 按照指定id查询并维护顺序
func QueryAndOrderByIDs(ids []int)(users []User, err error){
	// 动态填充id
	strIDs := make([]string, 0, len(ids))
	for _, id := range ids {
		strIDs = append(strIDs, fmt.Sprintf("%d", id))
	}
	query, args, err := sqlx.In("SELECT name, age FROM user WHERE id IN (?) ORDER BY FIND_IN_SET(id, ?)", ids, strings.Join(strIDs, ","))
	if err != nil {
		return
	}
	// sqlx.In 返回带 `?` bindvar的查询语句, 我们使用Rebind()重新绑定它
	query = DB.Rebind(query)
	err = DB.Select(&users, query, args...)
	return
}
// 第四:mian函数调用
func main() {
	err := initDB()
	if err != nil {
		panic(err)
	}
	defer DB.Close()
	// 1. 用代码去做排序
	// 2. 让MySQL排序
	fmt.Println("----")
	users ,err := QueryAndOrderByIDs([]int{7,5,6, 1})
	if err != nil {
		fmt.Printf("QueryByIDs failed, err:%v\n", err)
		return
	}
	for _, user := range users{
		fmt.Printf("user:%#v\n", user)
	}
}
/*
----
user:main.User{Name:"wangwu", Age:18}
user:main.User{Name:"zhaoliu", Age:28}
user:main.User{Name:"sunqi", Age:38}
user:main.User{Name:"沙河小王子", Age:20}
 */
 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
63
64
65
66
67
68
69
70
71
72
73
74
75
76
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
63
64
65
66
67
68
69
70
71
72
73
74
75
76
上次更新: 2024/3/13 15:35:10