之前客户有一个需求,需要用Go语言将一个服务器的MongoDB数据,定期同步到另一个服务器的SQL Server数据库中,由于两个数据库都采用了含有特殊字符的密码,因此踩了不少坑,特此来记录一下。
以mongo-driver连接MongoDB为例,使用前需要导入相关包,为了让大家看得直观一点,以下代码均采用硬编码方式将连接参数直接写出来
连接数据库的URI格式:“mongodb://{服务器IP地址}:{数据库端口号}”
import (
//此处省略其他包......
"context"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
func connectDatabase() {
var err error
var Option *options.ClientOptions
var Client *mongo.Client
var uri string
//URI格式:"mongodb://{服务器IP地址}:{数据库端口号}"
uri = "mongodb://127.0.0.1:27017"
Option = options.Client().ApplyURI(uri)
Client, err = mongo.Connect(Context, Option)
if err != nil {
log.Fatal(err)
}
err = Client.Ping(Context, nil)
if err != nil {
log.Fatal(err)
}
//Database()参数填你要连接的数据库名,此处为“test”
MongoDb = Client.Database("test")
}
带账户密码,且账户密码包含特殊字符(比如“+&=<>"#,%{}|^~[]`;/?:@$”),只需要修改一下URI格式。
连接数据库的URI格式:
“mongodb://{数据库用户名}:{数据库密码}@{服务器IP地址}:{数据库端口号}”
//URI格式:"mongodb://{数据库用户名}:{数据库密码}@{服务器IP地址}:{数据库端口号}"
//如:"mongodb://root:1234@127.0.0.1:27017"
//此处账户是root,密码是1234
uri = "mongodb://root:1234@127.0.0.1:27017"
Option = options.Client().ApplyURI(uri)
解决步骤:
1.先使用net/url包的QueryEscape()方法对特殊字符进行转义,构造正确的URI,作为参数传入ApplyURI()方法
2.构造Credential,写入数据库名、账号和密码,再使用SetAuth()方法,将Credential传进去
PS:个人猜测,由于有了Credential,里面已经写入了数据库名、账号和密码,向ApplyURI()方法传入的URI应该就不需要再加账户和密码了,只需要服务器IP和数据库端口号就行了,所以步骤1可能是多余的,大家可以自己去试一下,我这里就偷个懒不测了~
import (
//此处省略其他包......
"net/url"
)
// 对URI中数据库账号和密码中的特殊字符进行转义
func escapeCharacter(str string) string {
//省略部分代码......
if strings.ContainsAny(str, "+&=<>\"#,%{}|\\^~[]`;/?:@$") {
escapedUrlStr := url.QueryEscape(str)
return escapedUrlStr
}
//省略部分代码......
}
func connectDatabase() {
//省略部分代码......
//此处账户是@root,密码是@1234@,用户名和密码有特殊字符,需要转义
uri = "mongodb://" + escapeCharacter("@root") + ":" + escapeCharacter("@1234@") + "@127.0.0.1:27017"
var credential options.Credential
credential = options.Credential{
AuthSource: "test",
Username: "@root",
Password: "@1234@",
}
Option = options.Client().ApplyURI(uri).SetAuth(credential)
Client, err = mongo.Connect(Context, Option)
//省略部分代码......
}
前面已经获取了对MongoDB指定数据库的连接(通过Client.Database()方法会返回一个database的指针)现在要查询,只需要指定查询的表和查询条件即可。
首先使用bson对象构造查询条件,然后调用find()方法实现带条件查询,find()方法会返回一个游标,最后再循环调用find.Next()方法,不断访问游标查询到的文档(可以理解为关系型数据库的记录),并使用find.Decode()方法对获取的文档进行解码,然后根据你的需要进行下一步处理
操作之前需要导入bson包:“go.mongodb.org/mongo-driver/bson”
import (
//此处省略其他包......
"go.mongodb.org/mongo-driver/bson"
)
func (dlist *DataList) Query() {
//省略部分代码......
dlist.List = []Data{}
//选择要查询的表(集合)
var coll *mongo.Collection
coll = MongoDb.Collection("sys_user")
filter := bson.M{"status": "0"}
// 返回的是一个游标
find, err := coll.Find(context.TODO(), filter)
if err != nil {
log.Fatal("在XX表中查询数据出错", err)
return
}
// 查询完要关闭游标
defer find.Close(context.TODO())
// 不断访问游标获取查询到的文档
for find.Next(context.TODO()) {
row := Data{}
var getline interface{}
err = find.Decode(&getline)
if err != nil {
log.Fatal("解码XX表中的数据出错", err)
}
myline := []KeyVal{}
sByte, _ := json.Marshal(getline)
_ = json.Unmarshal(sByte, &myline)
//使用自定义方法GetMap()格式化数据
row.GetMap(myline)
dlist.List = append(dlist.List, row)
}
//省略部分代码......
}
修改和查询类似,首先使用bson对象构造修改的字段和修改的值,然后调用UpdateOne()或UpdateMany()方法(这俩方法分别对应修改单个文档和修改多个文档)执行修改操作
for index, item := range dataList {
//省略部分代码......
//在MongoDB中更新转移状态
c := MongoDb.Collection("sys_user")
//新的数据
updateData := bson.D{{"$set", bson.D{{"status", "1"}}}}
_, err = c.UpdateMany(Context, bson.D{{"id", item.Id}}, updateData)
if err != nil {
log.Fatal("更新XX表中第"+strconv.Itoa(index)+"条记录出错", err)
}
//省略部分代码......
}
import (
//此处省略其他包......
"database/sql"
_ "github.com/mattn/go-adodb"
)
//省略部分代码......
var SqlServerDb *sql.DB
var conf []string
conf = append(conf, "Provider=SQLOLEDB")
conf = append(conf, "Data Source=127.0.0.1,1433") // IP,端口号
conf = append(conf, "Initial Catalog=test") // 数据库名
conf = append(conf, "user id=sa") // 用户名
conf = append(conf, "password=root") // 密码
fmt.Println(strings.Join(conf, ";"))
SqlServerDb, err = sql.Open("adodb", strings.Join(conf, ";"))
if err != nil {
log.Fatal(err)
fmt.Println("访问SQL Server数据库失败", err)
return
}
//省略部分代码......
//省略部分代码......
conf = append(conf, "Provider=SQLOLEDB")
// sqlserver IP,端口号\实例名
conf = append(conf, "Data Source=127.0.0.1,1433\\admin")
conf = append(conf, "Initial Catalog=test") // 数据库名
conf = append(conf, "user id=@sa") // 用户名
conf = append(conf, "password=@root@") // 密码
fmt.Println(strings.Join(conf, ";"))
SqlServerDb, err = sql.Open("adodb", strings.Join(conf, ";"))
//省略部分代码......
SQL Server这类关系型数据库的增删改查比较常用,网上资料也比较多,本文就不赘述啦,这篇文章主要用于自己总结回顾,如果能给大家带来帮助自然是再好不过啦!