登录
首页 >  Golang >  Go问答

将 mongo-go-driver 与 Azure Cosmos DB 结合使用的事务出现意外行为

来源:stackoverflow

时间:2024-04-15 09:36:35 142浏览 收藏

珍惜时间,勤奋学习!今天给大家带来《将 mongo-go-driver 与 Azure Cosmos DB 结合使用的事务出现意外行为》,正文内容主要涉及到等等,如果你正在学习Golang,或者是对Golang有疑问,欢迎大家关注我!后面我会持续更新相关内容的,希望都能帮到正在学习的大家!

问题内容

我确信我遗漏了一些东西,但我无法让以下简单事务按预期工作。这种行为与我能找到的所有其他问题不同。

以下函数 multipleinsertstransaction() 的灵感来自于官方示例。

它成功写入一个文档,然后尝试写入第二个文档,这会返回错误,因为(故意)再次使用了相同的 id。

我的理解是,这些文档都没有保留在数据库中,因为我们从未达到 sc.committransaction(sc),因此 starttransaction()aborttransaction() 中的所有操作都应该回滚或不回滚甚至对其他会话可见。

然而,事实并非如此。第一个文档被写入,第二个文档按预期抛出错误,但函数返回后,第一个文档被持久化在数据库中。

这笔交易出了什么问题?我缺少什么?或者这是预期的?

package main

import (
    "context"
    "fmt"
    "go.mongodb.org/mongo-driver/bson"
    "go.mongodb.org/mongo-driver/bson/primitive"
    "go.mongodb.org/mongo-driver/mongo"
    "go.mongodb.org/mongo-driver/mongo/options"
    "go.mongodb.org/mongo-driver/mongo/readconcern"
    "go.mongodb.org/mongo-driver/mongo/writeconcern"
)

const (
    db = "test"
    coll = "test"
)

func main() {
    client, _ := mongo.connect(context.background(), options.client().applyuri(""))
    want, _ := client.database(db).collection(coll).countdocuments(context.background(), bson.m{})
    if err := multipleinsertstransaction(context.background(), client); err != nil {
        fmt.println("expected error occured...")
    }
    got, _ := client.database(db).collection(coll).countdocuments(context.background(), bson.m{})
    if got != want {
        fmt.printf("expected %d entries in database, but got %d", want, got)
        return
    }
    fmt.println("it worked!!")
}

func multipleinsertstransaction(ctx context.context, client *mongo.client) (err error) {
    return client.usesession(ctx, func(sc mongo.sessioncontext) error {
        err := sc.starttransaction(options.transaction().
            setreadconcern(readconcern.snapshot()).
            setwriteconcern(writeconcern.new(writeconcern.wmajority())),
        )
        if err != nil {
            return err
        }

        id := primitive.newobjectid()

        if _, err := client.database(db).collection(coll).insertone(sc, bson.m{"_id": id}); err != nil {
            sc.aborttransaction(sc)
            return err
        }

        if _, err := client.database(db).collection(coll).insertone(sc, bson.m{"_id": id}); err != nil {
            sc.aborttransaction(sc)
            return err
        }

        return sc.committransaction(sc)
    })
}

非常感谢!

我也尝试过不同的实现,但是(正如预期的那样)也没有运气:

package main

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

const (
    db = "test"
    coll = "test"
)

func main() {
    client, _ := mongo.Connect(context.Background(), options.Client().ApplyURI(""))
    want, _ := client.Database(db).Collection(coll).CountDocuments(context.Background(), bson.M{})
    if err := MultipleInsertsTransaction(context.Background(), client); err != nil {
        fmt.Println("expected error occured...")
    }
    got, _ := client.Database(db).Collection(coll).CountDocuments(context.Background(), bson.M{})
    if got != want {
        fmt.Printf("expected %d entries in database, but got %d", want, got)
        return
    }
    fmt.Println("it worked!!")
}

func MultipleInsertsTransaction(ctx context.Context, client *mongo.Client) (err error) {
    var session mongo.Session
    if session, err = client.StartSession(); err != nil {
        return err
    }
    defer session.EndSession(context.Background())

    id := primitive.NewObjectID()

    if _, err := session.WithTransaction(ctx, func(sc mongo.SessionContext) (interface{}, error) {

        if _, err := client.Database(db).Collection(coll).InsertOne(sc, bson.M{"_id": id}); err != nil {
            sc.AbortTransaction(sc)
            return nil, err
        }

        if _, err := client.Database(db).Collection(coll).InsertOne(sc, bson.M{"_id": id}); err != nil {
            sc.AbortTransaction(sc)
            return nil, err
        }
        return nil, nil
    }); err != nil {
        return err
    }
    return
}


解决方案


Azure CosmosDB 的 MongoDB API 仅与 MongoDB Wire Protocol 版本 3.6 兼容。它模拟与数据库的通信,核心数据库本身不是 MongoDB。

MongoDB multi-document transactions 是在版本 4.0(当前为 v4.2)中引入的。如果您使用支持事务和发送事务操作的 MongoDB 驱动程序,则当前 CosmosDB 不兼容。根据您的使用案例,您可能会发现 MongoDB Atlas 很有用。

今天关于《将 mongo-go-driver 与 Azure Cosmos DB 结合使用的事务出现意外行为》的内容介绍就到此结束,如果有什么疑问或者建议,可以在golang学习网公众号下多多回复交流;文中若有不正之处,也希望回复留言以告知!

声明:本文转载于:stackoverflow 如有侵犯,请联系study_golang@163.com删除
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>