03.sqlx库
# 01.sqlx基础
# 1.1 sqlx介绍
- 在项目中我们通常可能会使用
database/sql
连接MySQL数据库。 sqlx
可以认为是Go语言内置database/sql
的超集,它在优秀的内置database/sql
基础上提供了一组扩展。- 这些扩展中除了大家常用来查询的
Get(dest interface{}, ...) error
和Select(dest interface{}, ...) error
外还有很多其他强大的功能。
# 1.2 安装sqlx
go get github.com/jmoiron/sqlx
1
# 1.3 创建数据库
- 创建数据库
mysql> create database sql_demo charset utf8;
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
# 02.连接数据库
# 2.1 连接mysql
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
}
func main() {
if err := initDB();err!= nil{
fmt.Printf("init DB failed, err:%v\n", err)
return
}
fmt.Println("init DB success...")
}
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
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
# 2.2 结构体
type user struct {
ID int `db:"id"`
Age int `db:"age"`
Name string `db:"name"`
}
1
2
3
4
5
2
3
4
5
# 03.增删改查
# 3.1 查询单行数据
// 查询单条数据示例
func queryRowDemo() {
sqlStr := "select id, name, age from user where id=?"
var u user
err := db.Get(&u, sqlStr, 1)
if err != nil {
fmt.Printf("get failed, err:%v\n", err)
return
}
fmt.Printf("id:%d name:%s age:%d\n", u.ID, u.Name, u.Age)
}
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
# 3.2 查询多行数据
// 查询多条数据示例
func queryMultiRowDemo() {
sqlStr := "select id, name, age from user where id > ?"
var users []user
err := db.Select(&users, sqlStr, 0)
if err != nil {
fmt.Printf("query failed, err:%v\n", err)
return
}
fmt.Printf("users:%#v\n", users)
}
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
# 3.3 插入单条
// 插入数据
func insertRowDemo() {
sqlStr := "insert into user(name, age) values (?,?)"
ret, err := db.Exec(sqlStr, "沙河小王子", 19)
if err != nil {
fmt.Printf("insert failed, err:%v\n", err)
return
}
theID, err := ret.LastInsertId() // 新插入数据的id
if err != nil {
fmt.Printf("get lastinsert ID failed, err:%v\n", err)
return
}
fmt.Printf("insert success, the id is %d.\n", theID)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 3.4 更新
// 更新数据
func updateRowDemo() {
sqlStr := "update user set age=? where id = ?"
ret, err := db.Exec(sqlStr, 39, 6)
if err != nil {
fmt.Printf("update failed, err:%v\n", err)
return
}
n, err := ret.RowsAffected() // 操作影响的行数
if err != nil {
fmt.Printf("get RowsAffected failed, err:%v\n", err)
return
}
fmt.Printf("update success, affected rows:%d\n", n)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 3.5 删除
// 删除数据
func deleteRowDemo() {
sqlStr := "delete from user where id = ?"
ret, err := db.Exec(sqlStr, 6)
if err != nil {
fmt.Printf("delete failed, err:%v\n", err)
return
}
n, err := ret.RowsAffected() // 操作影响的行数
if err != nil {
fmt.Printf("get RowsAffected failed, err:%v\n", err)
return
}
fmt.Printf("delete success, affected rows:%d\n", n)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 04.其他操作
# 4.1 NamedExec插入
DB.NamedExec
方法用来绑定SQL语句与结构体或map中的同名字段。
func insertUserDemo()(err error){
sqlStr := "INSERT INTO user (name,age) VALUES (:name,:age)"
_, err = db.NamedExec(sqlStr,
map[string]interface{}{
"name": "李四",
"age": 28,
})
return
}
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
# 4.2 NamedQuery查询
- 与
DB.NamedExec
同理,这里是支持查询
# 4.2.1 法1:使用map做命名查询
func namedQuery(){
sqlStr := "SELECT * FROM user WHERE name=:name or age=:age"
// 使用map做命名查询
rows, err := db.NamedQuery(sqlStr, map[string]interface{}{"name": "张三","age":21})
if err != nil {
fmt.Printf("db.NamedQuery failed, err:%v\n", err)
return
}
defer rows.Close()
for rows.Next(){
var u user
err := rows.StructScan(&u)
if err != nil {
fmt.Printf("scan failed, err:%v\n", err)
continue
}
fmt.Printf("user:%#v\n", u)
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 4.2.2 法2:根据结构体字段
func namedQuery(){
sqlStr := "SELECT * FROM user WHERE name=:name"
u := user{
Name: "张三",
}
// 使用结构体命名查询,根据结构体字段的 db tag进行映射
rows, err := db.NamedQuery(sqlStr, u)
if err != nil {
fmt.Printf("db.NamedQuery failed, err:%v\n", err)
return
}
defer rows.Close()
for rows.Next(){
var u user
err := rows.StructScan(&u)
if err != nil {
fmt.Printf("scan failed, err:%v\n", err)
continue
}
fmt.Printf("user:%#v\n", u)
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 05.事务操作
对于事务操作,我们可以使用
sqlx
中提供的db.Beginx()
和tx.Exec()
方法。tx, err := db.Begin() // 开启事务 err = tx.Exec(...) // 执行 err = tx.Commit() // 提交 tx.Rollback() // 回滚
1
2
3
4
func transactionDemo2()(err error) {
// 1.开启事务
tx, err := db.Beginx() // 开启事务
if err != nil {
fmt.Printf("begin trans failed, err:%v\n", err)
return err
}
// 2.recover捕获 回滚
defer func() {
if p := recover(); p != nil { // recover不为空,回滚并触发异常
tx.Rollback()
panic(p)
} else if err != nil {
fmt.Println("rollback")
tx.Rollback() // 错误返回不为空,回滚
} else {
err = tx.Commit() // err is nil; if Commit returns error update err
fmt.Println("commit")
}
}()
// 3.修改 id=1 的用户年龄
sqlStr1 := "Update user set age=20 where id=?"
rs, err := tx.Exec(sqlStr1, 1)
if err!= nil{
return err
}
n, err := rs.RowsAffected()
if err != nil {
return err
}
if n != 1 {
return errors.New("exec sqlStr1 failed")
}
// 4.修改 id=2 的用户年龄
sqlStr2 := "Update user set age=50 where id=?"
rs, err = tx.Exec(sqlStr2, 3)
if err!=nil{
return err
}
n, err = rs.RowsAffected()
if err != nil {
return err
}
if n != 1 {
return errors.New("exec sqlStr1 failed")
}
return 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
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
上次更新: 2024/3/13 15:35:10