1. 准备表

创建数据库

1
create database go_db DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_general_ci;

创建表

1
2
3
4
5
CREATE TABLE user_tb1(
id INTEGER PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(20),
`password` VARCHAR(20)
)

添加数据

1
2
INSERT INTO user_tb1(username,password) VALUES("tom", "123");
INSERT INTO user_tb1(username,password) VALUES("kite", "456");

2. 安装驱动

1
go get -u github.com/go-sql-driver/mysql

初始化模块

1
go mod init m

更新依赖

1
go mod tidy

3. 获取连接

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package main

import (
"database/sql"
"time"

_ "github.com/go-sql-driver/mysql"
)

// ...

func main() {
db, err := sql.Open("mysql", "ops:xxx.@/go_db")
if err != nil {
panic(err)
}
// 最大连接时长
db.SetConnMaxLifetime(time.Minute * 3)
// 最大连接数
db.SetMaxOpenConns(10)
// 空闲连接数
db.SetMaxIdleConns(10)
}

初始化连接
Open函数可能只是验证其参数格式是否正确,实际上并不创建与数据库的连接。如果要检查数据源的名称是否真实有效。应该调用ping方法。

返回的DB对象可以安全的被多个goroutine并发使用,并且维护其自己的空闲连接池。因此,Open函数应该仅被调用一次,很少需要关闭这个DB对象

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
package main

import (
"database/sql"
"fmt"
"log"

_ "github.com/go-sql-driver/mysql"
)

// 定义一个全局对象db
var db *sql.DB

// 定义一个初始化数据库的函数
func initDB() error {
var err error
db, err = sql.Open("mysql", "ops:xxx.@tcp(192.168.10.10:3306)/go_db?charset=utf8mb4&parseTime=True")
if err != nil {
return err
}
// 最大连接时长
db.SetConnMaxLifetime(time.Minute * 3)
// 最大连接数
db.SetMaxOpenConns(10)
// 空闲连接数
db.SetMaxIdleConns(10)
// 尝试与数据库建立连接
err2 := db.Ping()
if err2 != nil {
return err2
}
return nil
}

func main() {
err := initDB()
if err != nil {
log.Fatal(err)
}
fmt.Println("初始化成功")
}

4. 插入数据

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
package main

import (
"database/sql"
"fmt"
"log"
"time"

_ "github.com/go-sql-driver/mysql"
)

// 定义一个全局对象db
var db *sql.DB

// 定义一个初始化数据库的函数
func initDB() error {
var err error
db, err = sql.Open("mysql", "ops:xxx.@tcp(192.168.10.10:3306)/go_db?charset=utf8mb4&parseTime=True")
if err != nil {
return err
}
// 最大连接时长
db.SetConnMaxLifetime(time.Minute * 3)
// 最大连接数
db.SetMaxOpenConns(10)
// 空闲连接数
db.SetMaxIdleConns(10)
// 尝试与数据库建立连接
err2 := db.Ping()
if err2 != nil {
return err2
}
return nil
}

// 插入数据
func insertData() {
sqlStr := "insert into user_tb1(username,password) values(?,?)"
ret, err := db.Exec(sqlStr, "张三", "zs123")
if err != nil {
log.Printf("insert failed, err: %v\n", err)
return
}
theID, err2 := ret.LastInsertId() // 新插入数据的id
if err2 != nil {
log.Printf("get lastinsert ID failed, err:%v\n", err)
return
}
fmt.Printf("theID: %v\n", theID)
}

func main() {
err := initDB()
if err != nil {
log.Fatal(err)
} else {
fmt.Println("初始化成功")
}

insertData()
}

5. 查询操作

单行查询db.QueryRow()执行一次查询,并期望返回最多一行结果(即Row)。QueryRow总是返回非nil的值,直到返回的Scan方法被调用时,才会返回被延迟的错误。

5.1 定义一个结构体

1
2
3
4
5
type user struct {
id int
username string
password string
}

5.2 单行查询

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
package main

import (
"database/sql"
"fmt"
"log"
"time"

_ "github.com/go-sql-driver/mysql"
)

// 定义一个全局对象db
var db *sql.DB

type user struct {
id int
username string
password string
}

// 定义一个初始化数据库的函数
func initDB() error {
var err error
db, err = sql.Open("mysql", "ops:xxx.@tcp(192.168.10.10:3306)/go_db?charset=utf8mb4&parseTime=True")
if err != nil {
return err
}
// 最大连接时长
db.SetConnMaxLifetime(time.Minute * 3)
// 最大连接数
db.SetMaxOpenConns(10)
// 空闲连接数
db.SetMaxIdleConns(10)
// 尝试与数据库建立连接
err2 := db.Ping()
if err2 != nil {
return err2
}
return nil
}

// 查询一条用户数据
func queryRowDemo() user {
sqlStr := "select id,username,password from user_tb1 where id=?"
var u user
// 确保QueryRow之后调用Scan方法,否则持有的数据库连接不会被释放
err := db.QueryRow(sqlStr, 1).Scan(&u.id, &u.username, &u.password)
if err != nil {
log.Printf("%v\n", err)
}
return u
}
func main() {
err := initDB()
if err != nil {
log.Fatal(err)
} else {
fmt.Println("初始化成功")
}

ret := queryRowDemo()
fmt.Printf("ret: %v\n", ret)
}

执行结果:

初始化成功
ret: {1 tom 123}

5.3 多行查询

多行查询db.Query()执行一次查询,返回多行结果(即Rows),一般用于执行select命令,参数args表示query中的展位参数

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
package main

import (
"database/sql"
"fmt"
"log"
"time"

_ "github.com/go-sql-driver/mysql"
)

// 定义一个全局对象db
var db *sql.DB

type user struct {
id int
username string
password string
}

// 定义一个初始化数据库的函数
func initDB() error {
var err error
db, err = sql.Open("mysql", "ops:xxx.@tcp(192.168.10.10:3306)/go_db?charset=utf8mb4&parseTime=True")
if err != nil {
return err
}
// 最大连接时长
db.SetConnMaxLifetime(time.Minute * 3)
// 最大连接数
db.SetMaxOpenConns(10)
// 空闲连接数
db.SetMaxIdleConns(10)
// 尝试与数据库建立连接
err2 := db.Ping()
if err2 != nil {
return err2
}
return nil
}

// 查询一条用户数据
func queryRowDemo(id int) []user {
sqlStr := "select id,username,password from user_tb1 where id>?"
// 确保QueryRow之后调用Scan方法,否则持有的数据库连接不会被释放
rows, err := db.Query(sqlStr, id)
if err != nil {
log.Printf("%v\n", err)
}
// 非常重要,关闭rows释放持有的数据库链接
defer rows.Close()

// 循环读取结果集中的数据
var u user
ret := make([]user, 0)
for rows.Next() {
err2 := rows.Scan(&u.id, &u.username, &u.password)
if err2 != nil {
log.Printf("scan failed, err:%v\n", err2)
}
ret = append(ret, u)
}
return ret
}
func main() {
err := initDB()
if err != nil {
log.Fatal(err)
} else {
fmt.Println("初始化成功")
}

ret := queryRowDemo(1)
fmt.Printf("ret: %v\n", ret)
}

运行结果:

初始化成功
ret: [{2 kite 456} {3 张三 zs123}]

5.4 更新操作

插入、更新和删除操作都是使用Exec方法

func (db *DB) Exec(query string, args ...interface{}) (Result, error)

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
package main

import (
"database/sql"
"fmt"
"log"
"time"

_ "github.com/go-sql-driver/mysql"
)

// 定义一个全局对象db
var db *sql.DB

type user struct {
id int
username string
password string
}

// 定义一个初始化数据库的函数
func initDB() error {
var err error
db, err = sql.Open("mysql", "ops:xxx.@tcp(192.168.10.10:3306)/go_db?charset=utf8mb4&parseTime=True")
if err != nil {
return err
}
// 最大连接时长
db.SetConnMaxLifetime(time.Minute * 3)
// 最大连接数
db.SetMaxOpenConns(10)
// 空闲连接数
db.SetMaxIdleConns(10)
// 尝试与数据库建立连接
err2 := db.Ping()
if err2 != nil {
return err2
}
return nil
}

// 更新操作
func updateData() {
sql := "update user_tb1 set username=?,password=? where id=?"
ret, err := db.Exec(sql, "kite2", "Kite123", "2")
if err != nil {
log.Printf("%v\n", err)
}
rows, err2 := ret.RowsAffected()
if err2 != nil {
log.Println("更新失败", err2)
}
fmt.Printf("更新成功,更新行数: %v\n", rows)
}
func main() {
err := initDB()
if err != nil {
log.Fatal(err)
} else {
fmt.Println("初始化成功")
}
updateData()
}

运行结果:

初始化成功
更新成功,更新行数: 1

5.5 删除操作

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
package main

import (
"database/sql"
"fmt"
"log"
"time"

_ "github.com/go-sql-driver/mysql"
)

// 定义一个全局对象db
var db *sql.DB

type user struct {
id int
username string
password string
}

// 定义一个初始化数据库的函数
func initDB() error {
var err error
db, err = sql.Open("mysql", "ops:xxx.@tcp(192.168.10.10:3306)/go_db?charset=utf8mb4&parseTime=True")
if err != nil {
return err
}
// 最大连接时长
db.SetConnMaxLifetime(time.Minute * 3)
// 最大连接数
db.SetMaxOpenConns(10)
// 空闲连接数
db.SetMaxIdleConns(10)
// 尝试与数据库建立连接
err2 := db.Ping()
if err2 != nil {
return err2
}
return nil
}

// 删除操作
func delData() {
sql := "delete from user_tb1 where id=?"
r, err := db.Exec(sql, "1")
if err != nil {
log.Printf("%v\n", err)
return
}
rows, err2 := r.RowsAffected()
if err2 != nil {
log.Printf("删除行失败,%v\n", err2)
return
}
fmt.Printf("删除成功,删除的行数: %v\n", rows)
}
func main() {
err := initDB()
if err != nil {
log.Fatal(err)
} else {
fmt.Println("初始化成功")
}
delData()
}

运行结果:

初始化成功
删除成功,删除的行数: 1