Golang学习笔记六-操作MySQL和Mongodb

Golang操作mysql数据库-准备数据库和表

下载安装MySQL

1
https://dev.mysql.com/downloads/mysql/

创建一个go_db数据库

1
create database go_db

打开数据库

1
use go_db

创建表

1
2
3
4
5
CREATE TABLE user_tbl (
id INTEGER PRIMARY KEY AUTO_INCREMENT,
username VARCHAR (20),
PASSWORD VARCHAR (20)
)

添加模拟数据

1
2
INSERT INTO user_tbl (username, PASSWORD) VALUES ("tom", "123")
INSERT INTO user_tbl (username, PASSWORD) VALUES ("kite", "456")

Golang操作mysql数据库-安装配置mysql驱动

安装驱动

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

初始化模块

1
go mod init [model]

执行go mod tidy

1
go mod tidy

导入驱动

1
2
3
4
5
6
7
8
9
10
11
package main

import (
"fmt"
"database/sql"
_ "github.com/go-sql-driver/mysql"
)

func main() {

}

Golang操作mysql数据库-获得数据库连接

导入包

1
2
3
4
5
6
7
package main

import (
"fmt"
"database/sql"
_ "github.com/go-sql-driver/mysql"
)

获得连接

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

import (
"database/sql"
_ "github.com/go-sql-driver/mysql"
"time"
)

func main() {
db, err := sql.Open("mysql", "root:123456@/go_db")
if err != nil {
panic(err)
}
print(db)
// 最大连接时长
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
package main

import (
"database/sql"
"fmt"
_ "github.com/go-sql-driver/mysql"
)

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

// 定义一个初始化数据库的函数
func initDB() (err error) {
dsn := "root:123456@tcp(127.0.0.1:3306)/go_db?charset=utf8mb4&parseTime=True"
// 不会校验账号密码是否正确
// 注意!!!这里不要使用:=,我们是给全局变量赋值,然后在main函数中使用全局变量db
db, err = sql.Open("mysql", dsn)
if err != nil {
return err
}
// 尝试与数据库建立连接(校验dsn是否正确)
err = db.Ping()
if err != nil {
return err
}
return nil
}

func main() {
err := initDB() // 调用输出化数据库的函数
if err != nil {
fmt.Printf("初始化失败!,err:%v\n", err)
return
}else{
fmt.Printf("初始化成功")
}
}

Golang操作mysql数据库-查询操作

单行查询

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

定义一个结构体

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

查询

1
2
3
4
5
6
7
8
9
10
11
12
// 查询一条用户数据
func queryRowDemo() {
sqlStr := "select id, username, password from user_tbl where id=?"
var u user
// 确保QueryRow之后调用Scan方法,否则持有的数据库链接不会被释放
err := db.QueryRow(sqlStr, 1).Scan(&u.id, &u.username, &u.password)
if err != nil {
fmt.Printf("scan failed, err:%v\n", err)
return
}
fmt.Printf("id:%d name:%s age:%s\n", u.id, u.username, u.password)
}

测试

1
2
3
4
5
6
7
8
9
10
func main() {
err := initDB() // 调用输出化数据库的函数
if err != nil {
fmt.Printf("初始化失败!,err:%v\n", err)
return
}else{
fmt.Printf("初始化成功")
}
queryRowDemo()
}

运行结果

1
初始化成功id:1 name:tom age:123

查询多行

多行查询 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
// 查询多条数据示例
func queryMultiRow() {
sqlStr := "select id, username, password from user_tbl where id > ?"
rows, err := db.Query(sqlStr, 0)
if err != nil {
fmt.Printf("query failed, err:%v\n", err)
return
}
// 非常重要:关闭rows释放持有的数据库链接
defer rows.Close()

// 循环读取结果集中的数据
for rows.Next() {
var u user
err := rows.Scan(&u.id, &u.username, &u.password)
if err != nil {
fmt.Printf("scan failed, err:%v\n", err)
return
}
fmt.Printf("id:%d username:%s password:%s\n", u.id, u.username, u.password)
}
}

运行结果

1
2
3
初始化成功
id:1 username:tom password:123
id:2 username:kite password:456

Golang操作mysql数据库-插入数据

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

1
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
// 插入数据
func insertData() {
sqlStr := "insert into user_tbl(username,password) values (?,?)"
ret, err := db.Exec(sqlStr, "张三", "zs123")
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
func main() {
err := initDB() // 调用输出化数据库的函数
if err != nil {
fmt.Printf("初始化失败!,err:%v\n", err)
return
}else{
fmt.Printf("初始化成功\n")
}
//queryRowDemo()
//queryMultiRow()
insertData()
}

运行结果

1
2
初始化成功
insert success, the id is 3.

Golang操作mysql数据库-删除数据

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

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

删除

1
2
3
4
5
6
7
8
9
10
11
12
13
14
func delData()  {
sql := "delete from user_tbl where id =?"
ret, err := db.Exec(sql, "1")
if err != nil {
fmt.Printf("删除失败, err:%v\n", err)
return
}
rows, err := ret.RowsAffected()
if err != nil {
fmt.Printf("删除行失败, err:%v\n", err)
return
}
fmt.Printf("删除成功, 删除的行数: %d.\n", rows)
}

测试

1
2
3
4
5
6
7
8
9
10
func main() {
err := initDB() // 调用输出化数据库的函数
if err != nil {
fmt.Printf("初始化失败!,err:%v\n", err)
return
}else{
fmt.Printf("初始化成功\n")
}
delData()
}

运行结果

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

Golang操作mysql数据库-更新数据

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

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

更新

1
2
3
4
5
6
7
8
9
10
11
12
13
14
func updateData()  {
sql := "update user_tbl set username=?, password=? where id=?"
ret, err := db.Exec(sql, "kite2", "kite123", "2")
if err != nil {
fmt.Printf("更新失败, err:%v\n", err)
return
}
rows, err := ret.RowsAffected()
if err != nil {
fmt.Printf("更新行失败, err:%v\n", err)
return
}
fmt.Printf("更新成功, 更新的行数: %d.\n", rows)
}

测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
func main() {
err := initDB() // 调用输出化数据库的函数
if err != nil {
fmt.Printf("初始化失败!,err:%v\n", err)
return
}else{
fmt.Printf("初始化成功\n")
}
//queryRowDemo()
//queryMultiRow()
//insertData()
//delData()
updateData()
}

运行结果

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

Golang操作MongoDB-下载安装MongoDB

下载地址:

1
https://www.mongodb.com/download-center/community

打开客户端

1
mongo.exe

创建数据库

1
use go_db;

创建集合

1
db.createCollection("student");

Golang操作MongoDB-下载安装驱动并连接数据库

下载地址:

1
https://www.mongodb.com/download-center/community

打开客户端

1
mongo.exe

创建数据库

1
use go_db;

创建集合

1
db.createCollection("student");

下载驱动

1
go get github.com/mongodb/mongo-go-driver

连接mongoDB

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

import (
"context"
"fmt"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
"log"
)


var client *mongo.Client

func initDB() {
// 设置客户端连接配置
clientOptions := options.Client().ApplyURI("mongodb://localhost:27017")
// 连接到MongoDB
var err error
client, err = mongo.Connect(context.TODO(), clientOptions)
if err != nil {
log.Fatal(err)
}
// 检查连接
err = client.Ping(context.TODO(), nil)
if err != nil {
log.Fatal(err)
}
fmt.Println("Connected to MongoDB!")
}

func main() {
initDB()
}

运行结果

1
Connected to MongoDB!

Golang操作MongoDB-BSON简介

MongoDB中的JSON文档存储在名为BSON(二进制编码的JSON)的二进制表示中。与其他将JSON数据存储为简单字符串和数字的数据库不同,BSON编码扩展了JSON表示,使其包含额外的类型,如int、long、date、浮点数和decimal128。这使得应用程序更容易可靠地处理、排序和比较数据。

连接MongoDB的Go驱动程序中有两大类型表示BSON数据:DRaw

类型 D家族被用来简洁地构建使用本地Go类型的BSON对象。这对于构造传递给MongoDB的命令特别有用。D家族包括四类:

  • D:一个BSON文档。这种类型应该在顺序重要的情况下使用,比如MongoDB命令。
  • M:一张无序的map。它和D是一样的,只是它不保持顺序。
  • A:一个BSON数组。
  • E:D里面的一个元素。

要使用BSON,需要先导入下面的包:

1
import "go.mongodb.org/mongo-driver/bson"

下面是一个使用D类型构建的过滤器 文档的例子,它可以用来查找name字段与’张三’或’李四’匹配的文档:

1
2
3
4
5
6
7
bson.D{{
"name",
bson.D{{
"$in",
bson.A{"张三", "李四"},
}},
}}

Raw类型家族用于验证字节切片。你还可以使用 Lookup()从原始类型检索单个元素。如果你不想要将BSON反序列化成另一种类型的开销,那么这是非常有用的。这个教程我们将只使用D类型。

Golang操作MongoDB-添加文档

创建一个结构体

1
2
3
4
type Student struct {
Name string
Age int
}

添加单个文档

使用 collection.InsertOne()方法插入一条文档记录:

1
2
3
4
5
6
7
8
9
func insertOne(s Student) {
initDB()
collection := client.Database("go_db").Collection("student")
insertResult, err := collection.InsertOne(context.TODO(), s)
if err != nil {
log.Fatal(err)
}
fmt.Println("Inserted a single document: ", insertResult.InsertedID)
}

测试

1
2
3
4
func main() {
s := Student{Name: "tom", Age: 20}
insertOne(s)
}

运行结果

1
2
Connected to MongoDB!
Inserted a single document: ObjectID("61124558682f5c9583330222")

客户端查看

1
2
3
4
mongodb 打开客户端
use go_db
db.student.find()
db.student.remove({}) // 删除所有

插入多个文档

使用 collection.InsertMany()方法插入多条文档记录:

1
2
3
4
5
6
7
8
9
10
func insertMore(students []interface{}) {
//students := []interface{}{s2, s3}
initDB()
collection := client.Database("go_db").Collection("student")
insertManyResult, err := collection.InsertMany(context.TODO(), students)
if err != nil {
log.Fatal(err)
}
fmt.Println("Inserted multiple documents: ", insertManyResult.InsertedIDs)
}

测试

1
2
3
4
5
6
7
func main() {
s := Student{Name: "tom", Age: 20}
s1 := Student{Name: "kite", Age: 21}
s2 := Student{Name: "rose", Age: 22}
students := []interface{}{s, s1, s2}
insertMore(students)
}

运行结果

1
2
Connected to MongoDB!
Inserted multiple documents: [ObjectID("611246c56637c3554426bc92") ObjectID("611246c56637c3554426bc93") ObjectID("611246c56637c3554426bc94")]

更多方法请查阅官方文档

Golang操作MongoDB-查找文档

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

import (
"context"
"fmt"
"log"
"time"

"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)

var client *mongo.Client
func initDB() {
// 设置客户端连接配置
clientOptions := options.Client().ApplyURI("mongodb://localhost:27017")

co := options.Client().ApplyURI("mongodb://localhost:27017")
mongo.Connect(context.TODO(), co)
// 连接到MongoDB
var err error
client, err = mongo.Connect(context.TODO(), clientOptions)
if err != nil {
log.Fatal(err)
}

client.Ping(context.TODO(), nil)
// 检查连接
err = client.Ping(context.TODO(), nil)
if err != nil {
log.Fatal(err)
}
fmt.Println("Connected to MongoDB!")
}

func find() {
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
collection := client.Database("go_db").Collection("student")
cur, err := collection.Find(ctx, bson.D{})
if err != nil {
log.Fatal(err)
}
defer cur.Close(ctx)
for cur.Next(ctx) {
var result bson.D
err := cur.Decode(&result)
if err != nil {
log.Fatal(err)
}
fmt.Printf("result: %v\n", result)
fmt.Printf("result.Map(): %v\n", result.Map()["name"])
}
if err := cur.Err(); err != nil {
log.Fatal(err)
}
}



func main() {
initDB()
find()
}

Golang操作MongoDB-更新文档

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

import (
"context"
"fmt"
"log"

"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)

type Student struct {
Name string
Age int
}

var client *mongo.Client

func initDb() {
co := options.Client().ApplyURI("mongodb://localhost:27017")
c, err := mongo.Connect(context.TODO(), co)
if err != nil {
log.Fatal(err)
}

err2 := c.Ping(context.TODO(), nil)
if err2 != nil {
log.Fatal(err2)
} else {
fmt.Println("连接成功!")
}
client = c
}

func update() {
ctx := context.TODO()
defer client.Disconnect(ctx)
c := client.Database("go_db").Collection("Student")

update := bson.D{{"$set", bson.D{{"Name", "big tom"}, {"Age", 22}}}}

ur, err := c.UpdateMany(ctx, bson.D{{"name", "tom"}}, update)
if err != nil {
log.Fatal(err)
}
fmt.Printf("ur.ModifiedCount: %v\n", ur.ModifiedCount)
}

func main() {
initDb()
update()
}

Golang操作MongoDB-删除文档

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

import (
"context"
"fmt"
"log"

"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)

type Student struct {
Name string
Age int
}

var client *mongo.Client

func initDb() {
co := options.Client().ApplyURI("mongodb://localhost:27017")
c, err := mongo.Connect(context.TODO(), co)
if err != nil {
log.Fatal(err)
}

err2 := c.Ping(context.TODO(), nil)
if err2 != nil {
log.Fatal(err2)
} else {
fmt.Println("连接成功!")
}
client = c
}

func del() {

initDb()
c := client.Database("go_db").Collection("Student")
ctx := context.TODO()

dr, err := c.DeleteMany(ctx, bson.D{{"Name", "big kite"}})

if err != nil {
log.Fatal(err)
}
fmt.Printf("ur.ModifiedCount: %v\n", dr.DeletedCount)

}

func main() {
del()
}