在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协程即可。

广告
将在 10 秒后关闭
bannerAds