首頁  >  文章  >  後端開發  >  在發生錯誤時省略 mongodb 事務回滾是個好習慣嗎

在發生錯誤時省略 mongodb 事務回滾是個好習慣嗎

WBOY
WBOY轉載
2024-02-06 10:12:08439瀏覽

在发生错误时省略 mongodb 事务回滚是一个好习惯吗

問題內容

我正在使用golang驅動程式go.mongodb.org/mongo-driver/mongo學習mongodb交易。我正在 github 上關注這個 so 答案和這個示例。

@simagix 給出的範例程式碼:

if session, err = client.StartSession(); err != nil {
    t.Fatal(err)
}
if err = session.StartTransaction(); err != nil {
    t.Fatal(err)
}
if err = mongo.WithSession(ctx, session, func(sc mongo.SessionContext) error {
    if result, err = collection.UpdateOne(sc, bson.M{"_id": id}, update); err != nil {
        t.Fatal(err)
    }
    if result.MatchedCount != 1 || result.ModifiedCount != 1 {
        t.Fatal("replace failed, expected 1 but got", result.MatchedCount)
    }

    // more interrelated operations ...

    if err = session.CommitTransaction(sc); err != nil {
        t.Fatal(err)
    }
    return nil
}); err != nil {
    t.Fatal(err)
}
session.EndSession(ctx)

在這兩個範例中,如果發生錯誤,它們都不會回滾。我知道這是一個演示樣本。但是當我在程式碼中執行相同操作時,它工作得很好。

在發生錯誤時是否可以省略回滾(驅動程式是否處理它)?還是我錯過了什麼?


正確答案


mongo.withsession() 確實不假設任何活動事務,它「僅」有幫助於在給定會話下運行回調。因此,如果您希望它作為啟動事務的一部分執行,您應該自己處理提交和中止。這樣可以進行更精細的控制。

但是,如果您打算將回調作為事務運行,則使用session.withtransaction() 因為它以透明的方式處理事務及其生命週期:它創建事務並根據回調返回的錯誤提交或中止它。作為額外的功能,它還可以處理重試。正如其文件也指出的那樣:

如果回呼失敗,驅動程式將呼叫aborttransaction。

這是一個如何在交易中正確執行回呼的簡單範例:

var docToInsert, idToUpdate, updateDoc any

func doInTransactionExample(ctx context.Context, client *mongo.Client) error {
    sess, err := client.StartSession(options.Session().SetDefaultReadConcern(readconcern.Majority()))
    if err != nil {
        return fmt.Errorf("client.StartSession() error: %w", err)
    }
    defer sess.EndSession(ctx)

    result, err := sess.WithTransaction(
        ctx,
        func(sessCtx mongo.SessionContext) (any, error) {
            // sessCtx must be used as context.Context for all operations to be run in the transaction.
            var ctx context.Context = sessCtx // Shadow ctx on purpose!

            c := client.Database("foo").Collection("bar")

            // Insert example
            if _, err := c.InsertOne(ctx, docToInsert); err != nil {
                return nil, fmt.Errorf("InsertOne() failed: %w", err)
            }

            // Update example
            if ur, err := c.UpdateByID(ctx, idToUpdate, updateDoc); err != nil {
                return nil, fmt.Errorf("UpdateByID() failed: %w", err)
            } else {
                if ur.MatchedCount == 0 {
                    return nil, fmt.Errorf("UpdateByID() failed: %w", mongo.ErrNoDocuments)
                }
            }

            return "arbitrary-result-to-return", nil
        },
        options.Transaction().SetReadPreference(readpref.PrimaryPreferred()),
    )

    if err != nil {
        return fmt.Errorf("sess.WithTransaction() error: %w", err)
    }

    _ = result // Not using result

    return nil
}

以上是在發生錯誤時省略 mongodb 事務回滾是個好習慣嗎的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:stackoverflow.com。如有侵權,請聯絡admin@php.cn刪除