在Go语言中使用MongoDB的事务
我尝试了从Go语言(1.12.1)中使用MongoDB事务。
使用Go语言操作MongoDB有几种方法,其中包括使用官方驱动和流行的mgo库。但是目前看来,mgo库似乎不支持事务处理,因此我将介绍使用官方驱动的方法。
准备支持事务的MongoDB。
可以在之前写的文章中很快创建
提前创建收藏夹
在MongoDB中,当插入数据时,会自动创建数据库和集合的功能,但似乎无法在事务中使用。因此,请提前准备好数据库和集合。
您可以打开MongoDB的shell,并使用命令创建一个Collection。如果您是按照上面链接中的文章所述使用Docker来启动MongoDB的话,那就按照那篇文章的方法来添加。
docker exec -it コンテナ名 mongo
请以类似的方式启动Shell。在MongoDB的Shell中,请
use 作成するDB名
决定一个数据库名称作为
db.createCollection("作成するコレクション名")
那么,我会创建一个空集合。只需要这些,所以我会使用quit命令退出Mongo的shell。
准备图书馆
使用go mod很流行,但是如果想在VSCode中实现自动补全,最终还是需要用go get的(´・ω・`)
go get -u go.mongodb.org/mongo-driver/mongo
go get -u go.mongodb.org/mongo-driver/bson
写代码
导入库的部分。
在使用mongo进行连接时,我们需要一起导入上下文(context)。
import (
"context"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
连接到MongoDB
在ApplyURI的参数中指定连接目标。如果要使用Docker容器中的MongoDB,请指定容器的IP地址。
// MongoDBへの接続
ctx := context.Background()
client, err := mongo.Connect(ctx, options.Client().ApplyURI("mongodb://MongoDBのIPアドレス:ポート番号(省略可)"))
if err != nil {
panic(err)
}
使用会话
在选择公式驱动器的方法时有许多不同的方式,很难确定选择哪一个是最好的,但是使用UseSession可能是最清晰的选择。因为在UseSession的实现中有一个代码 defer defaultSess.EndSession(ctx),所以我似乎不需要自己编写EndSession。
// セッション開始
err = client.UseSession(ctx, func(sc mongo.SessionContext) error {
// ここにトランザクションの処理を書く
})
if err != nil {
panic(err)
}
使用交易
在UseSession的回调函数中,可以编写处理事务的代码。通过使用接收到的SessionContext类型的上下文参数,可以实现事务。
// ここからトランザクション開始
err = sc.StartTransaction()
if err != nil {
return err
}
// DBとCollection名はここで指定
db := client.Database("DB名")
collection := db.Collection("コレクション名")
// 適当にInsert文などを。context型を求める引数にSessionContextを使うのが重要
_, err = collection.InsertOne(sc, bson.M{"キー": 値})
if err != nil {
// EndSession内でAbortTransactionが呼ばれるので、ここで無理に呼ぶ必要はない。
sc.AbortTransaction(sc)
return err
}
// トランザクション中の処理を確定
return sc.CommitTransaction(sc)
总结的样本
package main
import (
"context"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
func main() {
// MongoDBへの接続
ctx := context.Background()
client, err := mongo.Connect(ctx, options.Client().ApplyURI("mongodb://172.17.0.2:27017"))
if err != nil {
panic(err)
}
// セッション開始
err = client.UseSession(ctx, func(sc mongo.SessionContext) error {
// ここからトランザクション開始
err = sc.StartTransaction()
if err != nil {
return err
}
// DBとCollection名はここで指定
db := client.Database("my_test_db")
collection := db.Collection("my_test_col")
// 適当にInsert文などをば。引数にSessionContextを入れているのが重要
_, err = collection.InsertOne(sc, bson.M{"number": "abc"})
if err != nil {
// EndSession内でAbortTransactionが呼ばれるので、ここで無理に呼ぶ必要はない。
sc.AbortTransaction(sc)
return err
}
// トランザクション中の処理を確定
return sc.CommitTransaction(sc)
})
if err != nil {
panic(err)
}
}
结束了
会话部分用回调函数有些让人困惑,但不像JavaScript那样是异步的,所以还算好用。哦,要是想要异步的话,只需将UseSession附近改为Go协程即可。