Golang 操作数据库

数据库连接和驱动

安装数据库驱动包

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&...&paramN=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("连接数据库成功!")  
  
}

输出结果:

1
连接数据库成功!

数据库操作

查询数据库

使用 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 事务主要用于处理操作量大,复杂度高的数据。比如说,在人员管理系统中,你删除一个人员,你既需要删除人员的基本资料,也要删除和该人员相关的信息,如信箱,文章等等,这样,这些数据库操作语句就构成一个事务!

0%