首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用Azure Cosmos DB使用mongo-go驱动程序的事务的意外行为

使用Azure Cosmos DB使用mongo-go驱动程序的事务的意外行为
EN

Stack Overflow用户
提问于 2020-03-05 04:05:40
回答 1查看 380关注 0票数 1

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

下面的函数MultipleInsertsTransaction()是受官方例子启发的。

它成功地写入一个文档,然后尝试编写第二个文档,该文档返回一个错误,因为再次使用相同的ID (有意)。

我的理解是,这些文档中没有一个保存在数据库中,因为我们从未到达sc.CommitTransaction(sc),因此StartTransaction()AbortTransaction()中的所有操作都应该回滚,或者更确切地说,对其他会话不可见。

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

这个事务有什么问题吗?我遗漏了什么?或者这是意料之中的?

代码语言:javascript
复制
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("<put replica set connection string here>"))
    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)
    })
}

非常感谢!

我也尝试过不同的实现,但(如预期的)也没有成功:

代码语言:javascript
复制
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("<put replica set connection string here>"))
    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
}
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2020-03-07 05:39:18

Azure的MongoDB API只兼容于MongoDB线协议版本3.6。它模拟与数据库的通信,核心数据库本身不是MongoDB。

MongoDB多文档事务是在4.0版(目前的V4.2版)上引入的。如果您使用的是支持事务和发送事务性操作的MongoDB驱动程序,那么目前CosmosDB将无法与其兼容。根据您的用例,您可能会发现MongoDB地图集是有用的。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/60538045

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档