Home  >  Article  >  Backend Development  >  Is it a good practice to omit mongodb transaction rollback on error?

Is it a good practice to omit mongodb transaction rollback on error?

WBOY
WBOYforward
2024-02-06 10:12:08432browse

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

Question content

I am using golang drivergo.mongodb.org/mongo-driver/mongoLearning mongodb transactions. I'm following this so answer and this example on github.

Sample code given by @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)

In both examples, they will not rollback if an error occurs. I know this is a demo sample. But when I do the same in code, it works fine.

Is it possible to omit rollback when an error occurs (does the driver handle it)? Or am I missing something?


Correct Answer


##mongo.withsession() It does not assume any active transaction, it "only" helps To run the callback for a given session. Therefore, if you want it to be executed as part of the initiated transaction, you should handle the commit and abort yourself. This allows for finer control.

However, if you intend to run the callback as a transaction, use

session.withtransaction() because it handles transactions and their lifecycle in a transparent way: it creates the transaction and Submit or abort it based on the error returned by the callback. As an added feature, it can also handle retries. As its documentation also points out:

If the callback fails, the driver will call aborttransaction.

Here is a simple example of how to correctly execute callbacks within a transaction:

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
}

The above is the detailed content of Is it a good practice to omit mongodb transaction rollback on error?. For more information, please follow other related articles on the PHP Chinese website!

Statement:
This article is reproduced at:stackoverflow.com. If there is any infringement, please contact admin@php.cn delete