数据库连接和驱动
安装数据库驱动包
1
|
go get -u github.com/go-sql-driver/mysql
|
导入数据驱动
1
2
3
4
5
|
import (
"database/sql"
_ "github.com/go-sql-driver/mysql" //引用包内部分函数
)
|
sql.DB 结构体
sql.DB
结构是sql/database
包封装的一个数据库操作对象,包含了操作数据库的基本方法。
DSN
DSN
全称为Data Source Name
,表示数据库连来源,用于定义如何连接数据库,不同数据库的DSN格式是不同的,这取决于数据库驱动的实现,
下面是 go-sql-driver/sql
的DSN格式:
1
2
|
//[用户名[:密码]@][协议(数据库服务器地址)]]/数据库名称?参数列表
[username[:password]@][protocol[(address)]]/dbname[?param1=value1&...¶mN=valueN]
|
连接数据库
在 sql/database
包中.使用 sql.Open
来连接数据库,值得注意的是 sql.Open
这样连接不会验证密码和账户是否正确,数据库是否存在,只会校验 DSN 格式.
1
2
3
4
5
6
7
8
9
|
drever := "mysql"
//root为数据库用户名,后面为密码,tcp代表tcp协议,test处填写自己的数据库名称
DSN := "root:123123@tcp(127.0.0.1:3306)/godatabase?charset=utf8"
db, err := sql.Open(drever, DSN)
if err != nil { //不会校验用户名密码是否正确,只校验数据源格式
fmt.Printf("sql.Open err: %v", err) //dsn格式不正确时报错
return
}
|
验证账号密码以及要连接的数据库是否正确
使用 sql.Ping()
可以检验账号密码和数据库是否存在
1
2
3
4
5
|
err = db.Ping() //用来测试账号密码
if err != nil {
fmt.Printf("db.Ping err: %v", err)
return
}
|
完整代码:
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
|
package main
import (
"database/sql"
_ "github.com/go-sql-driver/mysql"
"fmt")
type info struct {
id int `db.id`
name string `db.name`
password int `db.password`
}
func main() {
drever := "mysql"
//root为数据库用户名,后面为密码,tcp代表tcp协议,test处填写自己的数据库名称
DSN := "root:123123@tcp(127.0.0.1:3306)/godatabase?charset=utf8"
db, err := sql.Open(drever, DSN)
if err != nil { //不会校验用户名密码是否正确,只校验数据源格式
fmt.Printf("sql.Open err: %v", err) //dsn格式不正确时报错
return
}
err = db.Ping() //用来测试账号密码
if err != nil {
fmt.Printf("db.Ping err: %v", err)
return
}
db.SetMaxOpenConns(5) //设置最大数据库连接数
fmt.Println("连接数据库成功!")
}
|
输出结果:
数据库操作
查询数据库
使用 sql.Query()
即可查询,和JAVA相同的是 都要传入SQL语句并且返回一个结果集.
而从结果集读出信息需要创建查询数据表对应的结构体,还需要用到读取结果集的语句
sql.Scan()
,值得注意的是,传入的结构体变量要转为指针,
结构体:
1
2
3
4
5
|
type info struct {
id int `db.id`
name string `db.name`
password int `db.password`
}
|
查询方法代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
func dbQuery(db *sql.DB, tableName string, inFo info) {
SQL := "SELECT * FROM " + tableName //SQL语句
rows, err := db.Query(SQL) //获得结果集
if err != nil { //捕获错误
fmt.Printf("db.Query err: %v", err)
return
}
for rows.Next() {
err := rows.Scan(&inFo.id, &inFo.name, &inFo.password) //从结果集中读取
if err != nil {
fmt.Printf("rows.Scan err: %v", err)
return
}
fmt.Println(inFo) //输出
}
rows.Close()
}
|
完整代码:
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
|
package main
import (
"database/sql"
_ "github.com/go-sql-driver/mysql"
"fmt")
type info struct {
id int `db.id`
name string `db.name`
password int `db.password`
}
func main() {
drever := "mysql"
//root为数据库用户名,后面为密码,tcp代表tcp协议,test处填写自己的数据库名称
DSN := "root:123123@tcp(127.0.0.1:3306)/godatabase?charset=utf8"
db, err := sql.Open(drever, DSN)
if err != nil { //不会校验用户名密码是否正确,只校验数据源格式
fmt.Printf("sql.Open err: %v", err) //dsn格式不正确时报错
return
}
err = db.Ping() //用来测试账号密码
if err != nil {
fmt.Printf("db.Ping err: %v", err)
return
}
db.SetMaxOpenConns(5) //设置最大数据库连接数
fmt.Println("连接数据库成功!")
fmt.Println("查询数据库")
var iNFO info
dbQuery(db, "userinfo", iNFO)
}
func dbQuery(db *sql.DB, tableName string, inFo info) {
SQL := "SELECT * FROM " + tableName
rows, err := db.Query(SQL) //获得结果集
if err != nil {
fmt.Printf("db.Query err: %v", err)
return
}
for rows.Next() {
err := rows.Scan(&inFo.id, &inFo.name, &inFo.password)
if err != nil {
fmt.Printf("rows.Scan err: %v", err)
return
}
fmt.Println(inFo)
}
rows.Close()
}
|
输出结果:
1
2
3
4
|
连接数据库成功!
查询数据库
{1 123 123123}
{2 1234 123123}
|
此外还有两两种常用操作:
QueryRow
表示只返回一行的查询,作为Query
的一个常见特例。
Prepare
表示准备一个需要多次使用的语句,供后续执行用。(预编译)
增加数据库条目
增加新条目需要使用 sql.Exec()
方法来实现,当然,也是要传入SQL语句的.
1
2
3
4
5
6
7
8
9
10
|
func dbExec(db *sql.DB) {
SQL := "INSERT INTO userinfo(name,password) VALUES (?,?)" //我的数据表ID设置为自增,所以设置了两个值
, err := db.Exec(SQL, 12, 1234) //添加新条目 ,会返回err
if err != nil {
fmt.Printf("db.Exec err: %v", err)
return
}
}
|
输出结果:
1
2
3
4
5
6
7
8
9
|
连接数据库成功!
查询数据库
{1 123 123123}
{2 1234 123123}
添加新条目
再次查询
{1 123 123123}
{2 1234 123123}
{4 12 1234}
|
更新数据库
数据库的更新也是和添加数据库条目相同,使用 sql.Exec()
+ SQL语句即可查询.
1
2
3
4
5
6
7
8
9
10
|
func dbUpdate(db *sql.DB) {
SQL := "UPDATE userinfo SET name where id=1"
_, err := db.Exec(SQL, "啊啊", 1)
if err != nil {
fmt.Printf("db Update err: %v", err)
return
}
}
|
输出结果:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
连接数据库成功!
查询数据库
{1 123 123123}
{2 1234 123123}
添加新条目
再次查询
{1 123 123123}
{2 1234 123123}
{6 12 1234}
更新后查询
{1 啊啊 123123}
{2 1234 123123}
{6 12 1234}
|
删除数据库条目
数据库条目的删除也是和添加数据库条目,更新数据库相同,使用 sql.Exec()
+ SQL语句即可查询.
1
2
3
4
5
6
7
8
9
10
|
func dbDelete(db *sql.DB) {
SQL := "DELETE FROM userinfo WHERE id= ? "
_, err := db.Exec(SQL, 7)
if err != nil {
fmt.Printf("db Delete err: %v", err)
return
}
}
|
输出结果:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
连接数据库成功!
查询数据库
{1 啊啊 123123}
{2 1234 123123}
{7 1234 1232}
添加新条目
添加后查询
{1 啊啊 123123}
{2 1234 123123}
{7 1234 1232}
{8 12 1234}
更新数据库
更新后查询
{1 啊啊 123123}
{2 1234 123123}
{7 1234 1232}
{8 12 1234}
删除数据库条目
删除后查询
{1 啊啊 123123}
{2 1234 123123}
{8 12 1234}
|
完整代码:
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
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
|
package main
import (
"database/sql"
_ "github.com/go-sql-driver/mysql"
"fmt")
type info struct {
id int `db.id`
name string `db.name`
password int `db.password`
}
func main() {
drever := "mysql"
//root为数据库用户名,后面为密码,tcp代表tcp协议,test处填写自己的数据库名称
DSN := "root:123123@tcp(127.0.0.1:3306)/godatabase?charset=utf8"
db, err := sql.Open(drever, DSN)
if err != nil { //不会校验用户名密码是否正确,只校验数据源格式
fmt.Printf("sql.Open err: %v", err) //dsn格式不正确时报错
return
}
err = db.Ping() //用来测试账号密码
if err != nil {
fmt.Printf("db.Ping err: %v", err)
return
}
db.SetMaxOpenConns(5) //设置最大数据库连接数
fmt.Println("连接数据库成功!")
fmt.Println("查询数据库")
var iNFO info
dbQuery(db, "userinfo", iNFO)
fmt.Println("添加新条目")
dbExec(db)
fmt.Println("添加后查询")
dbQuery(db, "userinfo", iNFO)
fmt.Println("更新数据库")
dbUpdate(db)
fmt.Println("更新后查询")
dbQuery(db, "userinfo", iNFO)
fmt.Println("删除数据库条目")
dbDelete(db)
fmt.Println("删除后查询")
dbQuery(db, "userinfo", iNFO)
}
func dbQuery(db *sql.DB, tableName string, inFo info) {
SQL := "SELECT * FROM " + tableName
rows, err := db.Query(SQL) //获得结果集
if err != nil {
fmt.Printf("db.Query err: %v", err)
return
}
for rows.Next() {
err := rows.Scan(&inFo.id, &inFo.name, &inFo.password)
if err != nil {
fmt.Printf("rows.Scan err: %v", err)
return
}
fmt.Println(inFo)
}
rows.Close()
}
func dbExec(db *sql.DB) {
SQL := "INSERT INTO userinfo(name,password) VALUES (?,?)"
_, err := db.Exec(SQL, 12, 1234)
if err != nil {
fmt.Printf("db.Exec err: %v", err)
return
}
}
func dbUpdate(db *sql.DB) {
SQL := "UPDATE userinfo SET name=? where id=?"
_, err := db.Exec(SQL, "啊啊", 1)
if err != nil {
fmt.Printf("db Update err: %v", err)
return
}
}
func dbDelete(db *sql.DB) {
SQL := "DELETE FROM userinfo WHERE id= ? "
_, err := db.Exec(SQL, 7)
if err != nil {
fmt.Printf("db Delete err: %v", err)
return
}
}
|
其他
MySQL事务
不过这这样一条一条的增删改查是非常繁琐的 ,这样高重复的 MySQL ,就构成了一个 事务.
具体的SQL事务,可以看这篇文章:
MySQL 事务 | 菜鸟教程 (runoob.com)
这里简单摘抄一句 MySQL事务 :
MySQL 事务主要用于处理操作量大,复杂度高的数据。比如说,在人员管理系统中,你删除一个人员,你既需要删除人员的基本资料,也要删除和该人员相关的信息,如信箱,文章等等,这样,这些数据库操作语句就构成一个事务!