> For the complete MongoDB documentation index, see www.mongodb.com/docs/llms.txt

# Transactions

In MongoDB, an operation on a single document is atomic. Because you can use embedded documents and arrays to capture relationships between data in a single document structure instead of normalizing across multiple documents and collections, multi-document transactions are not necessary for many practical use cases.

For situations that require atomicity of operations on multiple documents, MongoDB supports transactions. You can use transactions across multiple operations, collections, databases, documents, and shards.

## Transactions API

Use the language selector to set the language of the following example.

This example highlights the key components of the transactions API. In particular, it uses the callback API. The callback API:

- starts a transaction

- executes the specified operations

- commits the result or ends the transaction on error

Errors in server-side operations, such as the `DuplicateKeyError`, can end the transaction and result in a command error to alert the user that the transaction has ended. This behavior is expected and occurs even if the client never calls [`Session.abortTransaction()`](https://www.mongodb.com/docs/manual/reference/method/Session.abortTransaction.md#mongodb-method-Session.abortTransaction). To incorporate custom error handling, use the [Core API](https://www.mongodb.com/docs/manual/core/transactions-in-applications.md#std-label-txn-core-api) on your transaction.

The callback API incorporates retry logic for certain errors. The driver tries to rerun the transaction after a [TransientTransactionError](https://www.mongodb.com/docs/manual/core/transactions-in-applications.md#std-label-transient-transaction-error) or [UnknownTransactionCommitResult](https://www.mongodb.com/docs/manual/core/transactions-in-applications.md#std-label-unknown-transaction-commit-result) commit error.

Starting in MongoDB 6.2, the server does not retry the transaction if it receives a [TransactionTooLargeForCache](https://www.mongodb.com/docs/manual/core/transactions-in-applications.md#std-label-transactionTooLargeForCache-error) error.

Starting in MongoDB 8.1, if an `upsert` operation runs in a multidocument transaction, then the `upsert` does not retry when it encounters a duplicate key error.

**Important:**

- Use the MongoDB driver for your MongoDB version.

- When using drivers, each operation in the transaction must pass the session to each operation.

- Operations in a transaction use [transaction-level read concern](https://www.mongodb.com/docs/manual/core/transactions.md#std-label-transactions-read-concern), [transaction-level write concern](https://www.mongodb.com/docs/manual/core/transactions.md#std-label-transactions-write-concern), and [transaction-level read preference.](https://www.mongodb.com/docs/manual/core/transactions.md#std-label-transactions-read-preference)

- You can create collections in transactions implicitly or explicitly. See [Create Collections and Indexes in a Transaction.](https://www.mongodb.com/docs/manual/core/transactions.md#std-label-transactions-create-collections-indexes)

```python

# For a replica set, include the replica set name and a seedlist of the members in the URI string; e.g.
# uriString = 'mongodb://mongodb0.example.com:27017,mongodb1.example.com:27017/?replicaSet=myRepl'
# For a sharded cluster, connect to the mongos instances; e.g.
# uriString = 'mongodb://mongos0.example.com:27017,mongos1.example.com:27017/'

client = MongoClient(uriString)
wc_majority = WriteConcern("majority", wtimeout=1000)

# Prereq: Create collections.
client.get_database("mydb1", write_concern=wc_majority).foo.insert_one({"abc": 0})
client.get_database("mydb2", write_concern=wc_majority).bar.insert_one({"xyz": 0})

# Step 1: Define the callback that specifies the sequence of operations to perform inside the transactions.
def callback(session):
    collection_one = session.client.mydb1.foo
    collection_two = session.client.mydb2.bar

    # Important:: You must pass the session to the operations.
    collection_one.insert_one({"abc": 1}, session=session)
    collection_two.insert_one({"xyz": 999}, session=session)

# Step 2: Start a client session.
with client.start_session() as session:
    # Step 3: Use with_transaction to start a transaction, execute the callback, and commit (or abort on error).
    session.with_transaction(callback)

```

This example highlights the key components of the transactions API. In particular, it uses the callback API. The callback API:

- starts a transaction

- executes the specified operations

- commits the result or ends the transaction on error

Errors in server-side operations, such as the `DuplicateKeyError`, can end the transaction and result in a command error to alert the user that the transaction has ended. This behavior is expected and occurs even if the client never calls [`Session.abortTransaction()`](https://www.mongodb.com/docs/manual/reference/method/Session.abortTransaction.md#mongodb-method-Session.abortTransaction). To incorporate custom error handling, use the [Core API](https://www.mongodb.com/docs/manual/core/transactions-in-applications.md#std-label-txn-core-api) on your transaction.

The callback API incorporates retry logic for certain errors. The driver tries to rerun the transaction after a [TransientTransactionError](https://www.mongodb.com/docs/manual/core/transactions-in-applications.md#std-label-transient-transaction-error) or [UnknownTransactionCommitResult](https://www.mongodb.com/docs/manual/core/transactions-in-applications.md#std-label-unknown-transaction-commit-result) commit error.

Starting in MongoDB 6.2, the server does not retry the transaction if it receives a [TransactionTooLargeForCache](https://www.mongodb.com/docs/manual/core/transactions-in-applications.md#std-label-transactionTooLargeForCache-error) error.

Starting in MongoDB 8.1, if an `upsert` operation runs in a multidocument transaction, then the `upsert` does not retry when it encounters a duplicate key error.

**Important:**

- Use the MongoDB driver for your MongoDB version.

- When using drivers, each operation in the transaction must pass the session to each operation.

- Operations in a transaction use [transaction-level read concern](https://www.mongodb.com/docs/manual/core/transactions.md#std-label-transactions-read-concern), [transaction-level write concern](https://www.mongodb.com/docs/manual/core/transactions.md#std-label-transactions-write-concern), and [transaction-level read preference.](https://www.mongodb.com/docs/manual/core/transactions.md#std-label-transactions-read-preference)

- You can create collections in transactions implicitly or explicitly. See [Create Collections and Indexes in a Transaction.](https://www.mongodb.com/docs/manual/core/transactions.md#std-label-transactions-create-collections-indexes)

```java
String uri = "<your-connection-string>";
/*
  For a replica set, include the replica set name and a seedlist of the members in the URI string; e.g.
  String uri = "mongodb://mongodb0.example.com:27017,mongodb1.example.com:27017/admin?replicaSet=myRepl";
  For a sharded cluster, connect to the mongos instances.
  For example:
  String uri = "mongodb://mongos0.example.com:27017,mongos1.example.com:27017:27017/admin";
 */

final MongoClient client = MongoClients.create(uri);

/*
    Create collections.
 */

client.getDatabase("sample_mflix").getCollection("movies")
        .withWriteConcern(WriteConcern.MAJORITY).insertOne(new Document("title", "test"));
client.getDatabase("sample_mflix").getCollection("comments")
        .withWriteConcern(WriteConcern.MAJORITY).insertOne(new Document("text", "test"));

/* Step 1: Start a client session. */

final ClientSession clientSession = client.startSession();

/* Step 2: Optional. Define options to use for the transaction. */

TransactionOptions txnOptions = TransactionOptions.builder()
        .writeConcern(WriteConcern.MAJORITY)
        .build();

/* Step 3: Define the sequence of operations to perform inside the transactions. */

TransactionBody<String> txnBody = new TransactionBody<String>() {
    public String execute() {
        MongoCollection<Document> coll1 = client.getDatabase("sample_mflix").getCollection("movies");
        MongoCollection<Document> coll2 = client.getDatabase("sample_mflix").getCollection("comments");

        /*
           Important:: You must pass the session to the operations.
         */
        coll1.insertOne(clientSession, new Document("title", "test 2"));
        coll2.insertOne(clientSession, new Document("text", "test 2"));
        return "Inserted into collections in the same database";
    }
};
try {
    /*
       Step 4: Use .withTransaction() to start a transaction,
       execute the callback, and commit (or abort on error).
    */

    clientSession.withTransaction(txnBody, txnOptions);
} catch (RuntimeException e) {
    // some error handling
} finally {
    clientSession.close();
}

```

This example highlights the key components of the transactions API. In particular, it uses the callback API. The callback API:

- starts a transaction

- executes the specified operations

- commits the result or ends the transaction on error

Errors in server-side operations, such as the `DuplicateKeyError`, can end the transaction and result in a command error to alert the user that the transaction has ended. This behavior is expected and occurs even if the client never calls [`Session.abortTransaction()`](https://www.mongodb.com/docs/manual/reference/method/Session.abortTransaction.md#mongodb-method-Session.abortTransaction). To incorporate custom error handling, use the [Core API](https://www.mongodb.com/docs/manual/core/transactions-in-applications.md#std-label-txn-core-api) on your transaction.

The callback API incorporates retry logic for certain errors. The driver tries to rerun the transaction after a [TransientTransactionError](https://www.mongodb.com/docs/manual/core/transactions-in-applications.md#std-label-transient-transaction-error) or [UnknownTransactionCommitResult](https://www.mongodb.com/docs/manual/core/transactions-in-applications.md#std-label-unknown-transaction-commit-result) commit error.

Starting in MongoDB 6.2, the server does not retry the transaction if it receives a [TransactionTooLargeForCache](https://www.mongodb.com/docs/manual/core/transactions-in-applications.md#std-label-transactionTooLargeForCache-error) error.

Starting in MongoDB 8.1, if an `upsert` operation runs in a multidocument transaction, then the `upsert` does not retry when it encounters a duplicate key error.

**Important:**

- Use the MongoDB driver for your MongoDB version.

- When using drivers, each operation in the transaction must pass the session to each operation.

- Operations in a transaction use [transaction-level read concern](https://www.mongodb.com/docs/manual/core/transactions.md#std-label-transactions-read-concern), [transaction-level write concern](https://www.mongodb.com/docs/manual/core/transactions.md#std-label-transactions-write-concern), and [transaction-level read preference.](https://www.mongodb.com/docs/manual/core/transactions.md#std-label-transactions-read-preference)

- You can create collections in transactions implicitly or explicitly. See [Create Collections and Indexes in a Transaction.](https://www.mongodb.com/docs/manual/core/transactions.md#std-label-transactions-create-collections-indexes)

```javascript

  // For a replica set, include the replica set name and a seedlist of the members in the URI string; e.g.
  // const uri = 'mongodb://mongodb0.example.com:27017,mongodb1.example.com:27017/?replicaSet=myRepl'
  // For a sharded cluster, connect to the mongos instances; e.g.
  // const uri = 'mongodb://mongos0.example.com:27017,mongos1.example.com:27017/'

  const client = new MongoClient(uri);
  await client.connect();

  // Prereq: Create collections.

  await client
    .db('mydb1')
    .collection('foo')
    .insertOne({ abc: 0 }, { writeConcern: { w: 'majority' } });

  await client
    .db('mydb2')
    .collection('bar')
    .insertOne({ xyz: 0 }, { writeConcern: { w: 'majority' } });

  // Step 1: Start a Client Session
  const session = client.startSession();

  // Step 2: Optional. Define options to use for the transaction
  const transactionOptions = {
    readPreference: 'primary',
    readConcern: { level: 'local' },
    writeConcern: { w: 'majority' }
  };

  // Step 3: Use withTransaction to start a transaction, execute the callback, and commit (or abort on error)
  // Note: The callback for withTransaction MUST be async and/or return a Promise.
  try {
    await session.withTransaction(async () => {
      const coll1 = client.db('mydb1').collection('foo');
      const coll2 = client.db('mydb2').collection('bar');

      // Important:: You must pass the session to the operations

      await coll1.insertOne({ abc: 1 }, { session });
      await coll2.insertOne({ xyz: 999 }, { session });
    }, transactionOptions);
  } finally {
    await session.endSession();
    await client.close();
  }
```

This example highlights the key components of the transactions API. In particular, it uses the callback API. The callback API:

- starts a transaction

- executes the specified operations

- commits the result or ends the transaction on error

Errors in server-side operations, such as the `DuplicateKeyError`, can end the transaction and result in a command error to alert the user that the transaction has ended. This behavior is expected and occurs even if the client never calls [`Session.abortTransaction()`](https://www.mongodb.com/docs/manual/reference/method/Session.abortTransaction.md#mongodb-method-Session.abortTransaction). To incorporate custom error handling, use the [Core API](https://www.mongodb.com/docs/manual/core/transactions-in-applications.md#std-label-txn-core-api) on your transaction.

The callback API incorporates retry logic for certain errors. The driver tries to rerun the transaction after a [TransientTransactionError](https://www.mongodb.com/docs/manual/core/transactions-in-applications.md#std-label-transient-transaction-error) or [UnknownTransactionCommitResult](https://www.mongodb.com/docs/manual/core/transactions-in-applications.md#std-label-unknown-transaction-commit-result) commit error.

Starting in MongoDB 6.2, the server does not retry the transaction if it receives a [TransactionTooLargeForCache](https://www.mongodb.com/docs/manual/core/transactions-in-applications.md#std-label-transactionTooLargeForCache-error) error.

Starting in MongoDB 8.1, if an `upsert` operation runs in a multidocument transaction, then the `upsert` does not retry when it encounters a duplicate key error.

**Important:**

- Use the MongoDB driver for your MongoDB version.

- When using drivers, each operation in the transaction must pass the session to each operation.

- Operations in a transaction use [transaction-level read concern](https://www.mongodb.com/docs/manual/core/transactions.md#std-label-transactions-read-concern), [transaction-level write concern](https://www.mongodb.com/docs/manual/core/transactions.md#std-label-transactions-write-concern), and [transaction-level read preference.](https://www.mongodb.com/docs/manual/core/transactions.md#std-label-transactions-read-preference)

- You can create collections in transactions implicitly or explicitly. See [Create Collections and Indexes in a Transaction.](https://www.mongodb.com/docs/manual/core/transactions.md#std-label-transactions-create-collections-indexes)

```php
/*
 * For a replica set, include the replica set name and a seedlist of the members in the URI string; e.g.
 * uriString = 'mongodb://mongodb0.example.com:27017,mongodb1.example.com:27017/?replicaSet=myRepl'
 * For a sharded cluster, connect to the mongos instances; e.g.
 * uriString = 'mongodb://mongos0.example.com:27017,mongos1.example.com:27017/'
 */

$client = new \MongoDB\Client($uriString);

// Prerequisite: Create collections.
$client->selectCollection(
    'mydb1',
    'foo',
    [
        'writeConcern' => new \MongoDB\Driver\WriteConcern(\MongoDB\Driver\WriteConcern::MAJORITY, 1000),
    ],
)->insertOne(['abc' => 0]);

$client->selectCollection(
    'mydb2',
    'bar',
    [
        'writeConcern' => new \MongoDB\Driver\WriteConcern(\MongoDB\Driver\WriteConcern::MAJORITY, 1000),
    ],
)->insertOne(['xyz' => 0]);

// Step 1: Define the callback that specifies the sequence of operations to perform inside the transactions.

$callback = function (\MongoDB\Driver\Session $session) use ($client): void {
    $client
        ->selectCollection('mydb1', 'foo')
        ->insertOne(['abc' => 1], ['session' => $session]);

    $client
        ->selectCollection('mydb2', 'bar')
        ->insertOne(['xyz' => 999], ['session' => $session]);
};

// Step 2: Start a client session.

$session = $client->startSession();

// Step 3: Use with_transaction to start a transaction, execute the callback, and commit (or abort on error).

\MongoDB\with_transaction($session, $callback);

```

This example highlights the key components of the transactions API. In particular, it uses the callback API. The callback API:

- starts a transaction

- executes the specified operations

- commits the result or ends the transaction on error

Errors in server-side operations, such as the `DuplicateKeyError`, can end the transaction and result in a command error to alert the user that the transaction has ended. This behavior is expected and occurs even if the client never calls [`Session.abortTransaction()`](https://www.mongodb.com/docs/manual/reference/method/Session.abortTransaction.md#mongodb-method-Session.abortTransaction). To incorporate custom error handling, use the [Core API](https://www.mongodb.com/docs/manual/core/transactions-in-applications.md#std-label-txn-core-api) on your transaction.

The callback API incorporates retry logic for certain errors. The driver tries to rerun the transaction after a [TransientTransactionError](https://www.mongodb.com/docs/manual/core/transactions-in-applications.md#std-label-transient-transaction-error) or [UnknownTransactionCommitResult](https://www.mongodb.com/docs/manual/core/transactions-in-applications.md#std-label-unknown-transaction-commit-result) commit error.

Starting in MongoDB 6.2, the server does not retry the transaction if it receives a [TransactionTooLargeForCache](https://www.mongodb.com/docs/manual/core/transactions-in-applications.md#std-label-transactionTooLargeForCache-error) error.

Starting in MongoDB 8.1, if an `upsert` operation runs in a multidocument transaction, then the `upsert` does not retry when it encounters a duplicate key error.

**Important:**

- Use the MongoDB driver for your MongoDB version.

- When using drivers, each operation in the transaction must pass the session to each operation.

- Operations in a transaction use [transaction-level read concern](https://www.mongodb.com/docs/manual/core/transactions.md#std-label-transactions-read-concern), [transaction-level write concern](https://www.mongodb.com/docs/manual/core/transactions.md#std-label-transactions-write-concern), and [transaction-level read preference.](https://www.mongodb.com/docs/manual/core/transactions.md#std-label-transactions-read-preference)

- You can create collections in transactions implicitly or explicitly. See [Create Collections and Indexes in a Transaction.](https://www.mongodb.com/docs/manual/core/transactions.md#std-label-transactions-create-collections-indexes)

```csharp
// For a replica set, include the replica set name and a seedlist of the members in the URI string; e.g.
// string uri = "mongodb://mongodb0.example.com:27017,mongodb1.example.com:27017/?replicaSet=myRepl";
// For a sharded cluster, connect to the mongos instances; e.g.
// string uri = "mongodb://mongos0.example.com:27017,mongos1.example.com:27017/";
var client = new MongoClient(connectionString);

// Prereq: Create collections.
var database1 = client.GetDatabase("mydb1");
var collection1 = database1.GetCollection<BsonDocument>("foo").WithWriteConcern(WriteConcern.WMajority);
collection1.InsertOne(new BsonDocument("abc", 0));

var database2 = client.GetDatabase("mydb2");
var collection2 = database2.GetCollection<BsonDocument>("bar").WithWriteConcern(WriteConcern.WMajority);
collection2.InsertOne(new BsonDocument("xyz", 0));

// Step 1: Start a client session.
using (var session = client.StartSession())
{
    // Step 2: Optional. Define options to use for the transaction.
    var transactionOptions = new TransactionOptions(
        writeConcern: WriteConcern.WMajority);

    // Step 3: Define the sequence of operations to perform inside the transactions
    var cancellationToken = CancellationToken.None; // normally a real token would be used
    result = session.WithTransaction(
        (s, ct) =>
        {
            try
            {
                collection1.InsertOne(s, new BsonDocument("abc", 1), cancellationToken: ct);
                collection2.InsertOne(s, new BsonDocument("xyz", 999), cancellationToken: ct);
            }
            catch (MongoWriteException)
            {
                // Do something in response to the exception
                throw; // NOTE: You must rethrow the exception otherwise an infinite loop can occur.
            }
            return "Inserted into collections in different databases";
        },
        transactionOptions,
        cancellationToken);
}
```

This example highlights the key components of the transactions API. In particular, it uses the callback API. The callback API:

- starts a transaction

- executes the specified operations

- commits the result or ends the transaction on error

Errors in server-side operations, such as the `DuplicateKeyError`, can end the transaction and result in a command error to alert the user that the transaction has ended. This behavior is expected and occurs even if the client never calls [`Session.abortTransaction()`](https://www.mongodb.com/docs/manual/reference/method/Session.abortTransaction.md#mongodb-method-Session.abortTransaction). To incorporate custom error handling, use the [Core API](https://www.mongodb.com/docs/manual/core/transactions-in-applications.md#std-label-txn-core-api) on your transaction.

The callback API incorporates retry logic for certain errors. The driver tries to rerun the transaction after a [TransientTransactionError](https://www.mongodb.com/docs/manual/core/transactions-in-applications.md#std-label-transient-transaction-error) or [UnknownTransactionCommitResult](https://www.mongodb.com/docs/manual/core/transactions-in-applications.md#std-label-unknown-transaction-commit-result) commit error.

Starting in MongoDB 6.2, the server does not retry the transaction if it receives a [TransactionTooLargeForCache](https://www.mongodb.com/docs/manual/core/transactions-in-applications.md#std-label-transactionTooLargeForCache-error) error.

Starting in MongoDB 8.1, if an `upsert` operation runs in a multidocument transaction, then the `upsert` does not retry when it encounters a duplicate key error.

**Important:**

- Use the MongoDB driver for your MongoDB version.

- When using drivers, each operation in the transaction must pass the session to each operation.

- Operations in a transaction use [transaction-level read concern](https://www.mongodb.com/docs/manual/core/transactions.md#std-label-transactions-read-concern), [transaction-level write concern](https://www.mongodb.com/docs/manual/core/transactions.md#std-label-transactions-write-concern), and [transaction-level read preference.](https://www.mongodb.com/docs/manual/core/transactions.md#std-label-transactions-read-preference)

- You can create collections in transactions implicitly or explicitly. See [Create Collections and Indexes in a Transaction.](https://www.mongodb.com/docs/manual/core/transactions.md#std-label-transactions-create-collections-indexes)

```c
static bool
with_transaction_example(bson_error_t *error)
{
   mongoc_client_t *client = NULL;
   mongoc_write_concern_t *wc = NULL;
   mongoc_collection_t *coll = NULL;
   bool success = false;
   bool ret = false;
   bson_t *doc = NULL;
   bson_t *insert_opts = NULL;
   mongoc_client_session_t *session = NULL;
   mongoc_transaction_opt_t *txn_opts = NULL;

   /* For a replica set, include the replica set name and a seedlist of the
    * members in the URI string; e.g.
    * uri_repl = "mongodb://mongodb0.example.com:27017,mongodb1.example.com:" \
    *    "27017/?replicaSet=myRepl";
    * client = mongoc_client_new (uri_repl);
    * For a sharded cluster, connect to the mongos instances; e.g.
    * uri_sharded =
    * "mongodb://mongos0.example.com:27017,mongos1.example.com:27017/";
    * client = mongoc_client_new (uri_sharded);
    */

   client = get_client();

   /* Prereq: Create collections. Note Atlas connection strings include a majority write
    * concern by default.
    */
   wc = mongoc_write_concern_new();
   mongoc_write_concern_set_wmajority(wc, 1000);
   insert_opts = bson_new();
   mongoc_write_concern_append(wc, insert_opts);
   coll = mongoc_client_get_collection(client, "mydb1", "foo");
   doc = BCON_NEW("abc", BCON_INT32(0));
   ret = mongoc_collection_insert_one(coll, doc, insert_opts, NULL /* reply */, error);
   if (!ret) {
      goto fail;
   }
   bson_destroy(doc);
   mongoc_collection_destroy(coll);
   coll = mongoc_client_get_collection(client, "mydb2", "bar");
   doc = BCON_NEW("xyz", BCON_INT32(0));
   ret = mongoc_collection_insert_one(coll, doc, insert_opts, NULL /* reply */, error);
   if (!ret) {
      goto fail;
   }

   /* Step 1: Start a client session. */
   session = mongoc_client_start_session(client, NULL /* opts */, error);
   if (!session) {
      goto fail;
   }

   /* Step 2: Optional. Define options to use for the transaction. */
   txn_opts = mongoc_transaction_opts_new();
   mongoc_transaction_opts_set_write_concern(txn_opts, wc);

   /* Step 3: Use mongoc_client_session_with_transaction to start a transaction,
    * execute the callback, and commit (or abort on error). */
   ret = mongoc_client_session_with_transaction(session, callback, txn_opts, NULL /* ctx */, NULL /* reply */, error);
   if (!ret) {
      goto fail;
   }

   success = true;
fail:
   bson_destroy(doc);
   mongoc_collection_destroy(coll);
   bson_destroy(insert_opts);
   mongoc_write_concern_destroy(wc);
   mongoc_transaction_opts_destroy(txn_opts);
   mongoc_client_session_destroy(session);
   mongoc_client_destroy(client);
   return success;
}

/* Define the callback that specifies the sequence of operations to perform
 * inside the transactions. */
static bool
callback(mongoc_client_session_t *session, void *ctx, bson_t **reply, bson_error_t *error)
{
   mongoc_client_t *client = NULL;
   mongoc_collection_t *coll = NULL;
   bson_t *doc = NULL;
   bson_t *opts = bson_new();
   bool success = false;
   bool ret = false;

   BSON_UNUSED(ctx);
   BSON_UNUSED(reply);

   // Important::  The logical session ID MUST be applied to all associated operations.
   ret = mongoc_client_session_append(session, opts, error);
   if (!ret) {
      goto fail;
   }

   client = mongoc_client_session_get_client(session);
   coll = mongoc_client_get_collection(client, "mydb1", "foo");
   doc = BCON_NEW("abc", BCON_INT32(1));
   ret = mongoc_collection_insert_one(coll, doc, opts, NULL, error);
   if (!ret) {
      goto fail;
   }
   bson_destroy(doc);
   mongoc_collection_destroy(coll);
   coll = mongoc_client_get_collection(client, "mydb2", "bar");
   doc = BCON_NEW("xyz", BCON_INT32(999));
   ret = mongoc_collection_insert_one(coll, doc, opts, NULL, error);
   if (!ret) {
      goto fail;
   }

   success = true;
fail:
   mongoc_collection_destroy(coll);
   bson_destroy(opts);
   bson_destroy(doc);
   return success;
}
```

This example highlights the key components of the transactions API. In particular, it uses the callback API. The callback API:

- starts a transaction

- executes the specified operations

- commits the result or ends the transaction on error

Errors in server-side operations, such as the `DuplicateKeyError`, can end the transaction and result in a command error to alert the user that the transaction has ended. This behavior is expected and occurs even if the client never calls [`Session.abortTransaction()`](https://www.mongodb.com/docs/manual/reference/method/Session.abortTransaction.md#mongodb-method-Session.abortTransaction). To incorporate custom error handling, use the [Core API](https://www.mongodb.com/docs/manual/core/transactions-in-applications.md#std-label-txn-core-api) on your transaction.

The callback API incorporates retry logic for certain errors. The driver tries to rerun the transaction after a [TransientTransactionError](https://www.mongodb.com/docs/manual/core/transactions-in-applications.md#std-label-transient-transaction-error) or [UnknownTransactionCommitResult](https://www.mongodb.com/docs/manual/core/transactions-in-applications.md#std-label-unknown-transaction-commit-result) commit error.

Starting in MongoDB 6.2, the server does not retry the transaction if it receives a [TransactionTooLargeForCache](https://www.mongodb.com/docs/manual/core/transactions-in-applications.md#std-label-transactionTooLargeForCache-error) error.

Starting in MongoDB 8.1, if an `upsert` operation runs in a multidocument transaction, then the `upsert` does not retry when it encounters a duplicate key error.

**Important:**

- Use the MongoDB driver for your MongoDB version.

- When using drivers, each operation in the transaction must pass the session to each operation.

- Operations in a transaction use [transaction-level read concern](https://www.mongodb.com/docs/manual/core/transactions.md#std-label-transactions-read-concern), [transaction-level write concern](https://www.mongodb.com/docs/manual/core/transactions.md#std-label-transactions-write-concern), and [transaction-level read preference.](https://www.mongodb.com/docs/manual/core/transactions.md#std-label-transactions-read-preference)

- You can create collections in transactions implicitly or explicitly. See [Create Collections and Indexes in a Transaction.](https://www.mongodb.com/docs/manual/core/transactions.md#std-label-transactions-create-collections-indexes)

```cpp

// The mongocxx::instance constructor and destructor initialize and shut down the driver,
// respectively. Therefore, a mongocxx::instance must be created before using the driver and
// must remain alive for as long as the driver is in use.
mongocxx::instance inst{};

// For a replica set, include the replica set name and a seedlist of the members in the URI
// string; e.g.
// uriString =
// 'mongodb://mongodb0.example.com:27017,mongodb1.example.com:27017/?replicaSet=myRepl'
// For a sharded cluster, connect to the mongos instances; e.g.
// uriString = 'mongodb://mongos0.example.com:27017,mongos1.example.com:27017/'
mongocxx::client client{mongocxx::uri{}};

// Prepare to set majority write explicitly. Note: on Atlas deployments this won't always be
// needed. The suggested Atlas connection string includes majority write concern by default.
write_concern wc_majority{};
wc_majority.acknowledge_level(write_concern::level::k_majority);

// Prereq: Create collections.

auto foo = client["mydb1"]["foo"];
auto bar = client["mydb2"]["bar"];

try {
    options::insert opts;
    opts.write_concern(wc_majority);

    foo.insert_one(make_document(kvp("abc", 0)), opts);
    bar.insert_one(make_document(kvp("xyz", 0)), opts);
} catch (mongocxx::exception const& e) {
    std::cout << "An exception occurred while inserting: " << e.what() << std::endl;
    return EXIT_FAILURE;
}

// Step 1: Define the callback that specifies the sequence of operations to perform inside the
// transactions.
client_session::with_transaction_cb callback = [&](client_session* session) {
    // Important::  You must pass the session to the operations.
    foo.insert_one(*session, make_document(kvp("abc", 1)));
    bar.insert_one(*session, make_document(kvp("xyz", 999)));
};

// Step 2: Start a client session
auto session = client.start_session();

// Step 3: Use with_transaction to start a transaction, execute the callback,
// and commit (or abort on error).
try {
    options::transaction opts;
    opts.write_concern(wc_majority);

    session.with_transaction(callback, opts);
} catch (mongocxx::exception const& e) {
    std::cout << "An exception occurred: " << e.what() << std::endl;
    return EXIT_FAILURE;
}

return EXIT_SUCCESS;

```

This example highlights the key components of the transactions API. In particular, it uses the callback API. The callback API:

- starts a transaction

- executes the specified operations

- commits the result or ends the transaction on error

Errors in server-side operations, such as the `DuplicateKeyError`, can end the transaction and result in a command error to alert the user that the transaction has ended. This behavior is expected and occurs even if the client never calls [`Session.abortTransaction()`](https://www.mongodb.com/docs/manual/reference/method/Session.abortTransaction.md#mongodb-method-Session.abortTransaction). To incorporate custom error handling, use the [Core API](https://www.mongodb.com/docs/manual/core/transactions-in-applications.md#std-label-txn-core-api) on your transaction.

The callback API incorporates retry logic for certain errors. The driver tries to rerun the transaction after a [TransientTransactionError](https://www.mongodb.com/docs/manual/core/transactions-in-applications.md#std-label-transient-transaction-error) or [UnknownTransactionCommitResult](https://www.mongodb.com/docs/manual/core/transactions-in-applications.md#std-label-unknown-transaction-commit-result) commit error.

Starting in MongoDB 6.2, the server does not retry the transaction if it receives a [TransactionTooLargeForCache](https://www.mongodb.com/docs/manual/core/transactions-in-applications.md#std-label-transactionTooLargeForCache-error) error.

Starting in MongoDB 8.1, if an `upsert` operation runs in a multidocument transaction, then the `upsert` does not retry when it encounters a duplicate key error.

**Important:**

- Use the MongoDB driver for your MongoDB version.

- When using drivers, each operation in the transaction must pass the session to each operation.

- Operations in a transaction use [transaction-level read concern](https://www.mongodb.com/docs/manual/core/transactions.md#std-label-transactions-read-concern), [transaction-level write concern](https://www.mongodb.com/docs/manual/core/transactions.md#std-label-transactions-write-concern), and [transaction-level read preference.](https://www.mongodb.com/docs/manual/core/transactions.md#std-label-transactions-read-preference)

- You can create collections in transactions implicitly or explicitly. See [Create Collections and Indexes in a Transaction.](https://www.mongodb.com/docs/manual/core/transactions.md#std-label-transactions-create-collections-indexes)

```python

# For a replica set, include the replica set name and a seedlist of the members in the URI string; e.g.
# uriString = 'mongodb://mongodb0.example.com:27017,mongodb1.example.com:27017/?replicaSet=myRepl'
# For a sharded cluster, connect to the mongos instances; e.g.
# uriString = 'mongodb://mongos0.example.com:27017,mongos1.example.com:27017/'

client = AsyncIOMotorClient(uriString)
wc_majority = WriteConcern("majority", wtimeout=1000)

# Prereq: Create collections.
await client.get_database("mydb1", write_concern=wc_majority).foo.insert_one({"abc": 0})
await client.get_database("mydb2", write_concern=wc_majority).bar.insert_one({"xyz": 0})

# Step 1: Define the callback that specifies the sequence of operations to perform inside the transactions.
async def callback(my_session):
    collection_one = my_session.client.mydb1.foo
    collection_two = my_session.client.mydb2.bar

    # Important:: You must pass the session to the operations.
    await collection_one.insert_one({"abc": 1}, session=my_session)
    await collection_two.insert_one({"xyz": 999}, session=my_session)

# Step 2: Start a client session.
async with await client.start_session() as session:
    # Step 3: Use with_transaction to start a transaction, execute the callback, and commit (or abort on error).
    await session.with_transaction(
        callback,
        read_concern=ReadConcern("local"),
        write_concern=wc_majority,
        read_preference=ReadPreference.PRIMARY,
    )

```

This example highlights the key components of the transactions API. In particular, it uses the callback API. The callback API:

- starts a transaction

- executes the specified operations

- commits the result or ends the transaction on error

Errors in server-side operations, such as the `DuplicateKeyError`, can end the transaction and result in a command error to alert the user that the transaction has ended. This behavior is expected and occurs even if the client never calls [`Session.abortTransaction()`](https://www.mongodb.com/docs/manual/reference/method/Session.abortTransaction.md#mongodb-method-Session.abortTransaction). To incorporate custom error handling, use the [Core API](https://www.mongodb.com/docs/manual/core/transactions-in-applications.md#std-label-txn-core-api) on your transaction.

The callback API incorporates retry logic for certain errors. The driver tries to rerun the transaction after a [TransientTransactionError](https://www.mongodb.com/docs/manual/core/transactions-in-applications.md#std-label-transient-transaction-error) or [UnknownTransactionCommitResult](https://www.mongodb.com/docs/manual/core/transactions-in-applications.md#std-label-unknown-transaction-commit-result) commit error.

Starting in MongoDB 6.2, the server does not retry the transaction if it receives a [TransactionTooLargeForCache](https://www.mongodb.com/docs/manual/core/transactions-in-applications.md#std-label-transactionTooLargeForCache-error) error.

Starting in MongoDB 8.1, if an `upsert` operation runs in a multidocument transaction, then the `upsert` does not retry when it encounters a duplicate key error.

**Important:**

- Use the MongoDB driver for your MongoDB version.

- When using drivers, each operation in the transaction must pass the session to each operation.

- Operations in a transaction use [transaction-level read concern](https://www.mongodb.com/docs/manual/core/transactions.md#std-label-transactions-read-concern), [transaction-level write concern](https://www.mongodb.com/docs/manual/core/transactions.md#std-label-transactions-write-concern), and [transaction-level read preference.](https://www.mongodb.com/docs/manual/core/transactions.md#std-label-transactions-read-preference)

- You can create collections in transactions implicitly or explicitly. See [Create Collections and Indexes in a Transaction.](https://www.mongodb.com/docs/manual/core/transactions.md#std-label-transactions-create-collections-indexes)

```ruby

# For a replica set, include the replica set name and a seedlist of the members in the URI string; e.g.
# uriString = 'mongodb://mongodb0.example.com:27017,mongodb1.example.com:27017/?replicaSet=myRepl'
# For a sharded cluster, connect to the mongos instances; e.g.
# uri_string = 'mongodb://mongos0.example.com:27017,mongos1.example.com:27017/'

client = Mongo::Client.new(uri_string, write_concern: { w: :majority, wtimeout: 1000 })

# Prereq: Create collections.

client.use('mydb1')['foo'].insert_one(abc: 0)
client.use('mydb2')['bar'].insert_one(xyz: 0)

# Step 1: Define the callback that specifies the sequence of operations to perform inside the transactions.

callback = proc do |my_session|
  collection_one = client.use('mydb1')['foo']
  collection_two = client.use('mydb2')['bar']

  # Important: You must pass the session to the operations.

  collection_one.insert_one({ abc: 1 }, session: my_session)
  collection_two.insert_one({ xyz: 999 }, session: my_session)
end

# . Step 2: Start a client session.

session = client.start_session

# Step 3: Use with_transaction to start a transaction, execute the callback, and commit (or abort on error).

session.with_transaction(
  read_concern: { level: :local },
  write_concern: { w: :majority, wtimeout: 1000 },
  read: { mode: :primary },
  &callback
)

```

This example highlights the key components of the transactions API. In particular, it uses the callback API. The callback API:

- starts a transaction

- executes the specified operations

- commits the result or ends the transaction on error

Errors in server-side operations, such as the `DuplicateKeyError`, can end the transaction and result in a command error to alert the user that the transaction has ended. This behavior is expected and occurs even if the client never calls [`Session.abortTransaction()`](https://www.mongodb.com/docs/manual/reference/method/Session.abortTransaction.md#mongodb-method-Session.abortTransaction). To incorporate custom error handling, use the [Core API](https://www.mongodb.com/docs/manual/core/transactions-in-applications.md#std-label-txn-core-api) on your transaction.

The callback API incorporates retry logic for certain errors. The driver tries to rerun the transaction after a [TransientTransactionError](https://www.mongodb.com/docs/manual/core/transactions-in-applications.md#std-label-transient-transaction-error) or [UnknownTransactionCommitResult](https://www.mongodb.com/docs/manual/core/transactions-in-applications.md#std-label-unknown-transaction-commit-result) commit error.

Starting in MongoDB 6.2, the server does not retry the transaction if it receives a [TransactionTooLargeForCache](https://www.mongodb.com/docs/manual/core/transactions-in-applications.md#std-label-transactionTooLargeForCache-error) error.

Starting in MongoDB 8.1, if an `upsert` operation runs in a multidocument transaction, then the `upsert` does not retry when it encounters a duplicate key error.

**Important:**

- Use the MongoDB driver for your MongoDB version.

- When using drivers, each operation in the transaction must pass the session to each operation.

- Operations in a transaction use [transaction-level read concern](https://www.mongodb.com/docs/manual/core/transactions.md#std-label-transactions-read-concern), [transaction-level write concern](https://www.mongodb.com/docs/manual/core/transactions.md#std-label-transactions-write-concern), and [transaction-level read preference.](https://www.mongodb.com/docs/manual/core/transactions.md#std-label-transactions-read-preference)

- You can create collections in transactions implicitly or explicitly. See [Create Collections and Indexes in a Transaction.](https://www.mongodb.com/docs/manual/core/transactions.md#std-label-transactions-create-collections-indexes)

```rust

// Prereq: Create collections. CRUD operations in transactions must be on existing collections.

client
    .database("mydb1")
    .collection::<Document>("foo")
    .insert_one(doc! { "abc": 0})
    .await?;
client
    .database("mydb2")
    .collection::<Document>("bar")
    .insert_one(doc! { "xyz": 0})
    .await?;

// Step 1: Define the callback that specifies the sequence of operations to perform inside the
// transaction.
async fn callback(session: &mut ClientSession) -> Result<()> {
    let collection_one = session
        .client()
        .database("mydb1")
        .collection::<Document>("foo");
    let collection_two = session
        .client()
        .database("mydb2")
        .collection::<Document>("bar");

    // Important: You must pass the session to the operations.
    collection_one
        .insert_one(doc! { "abc": 1 })
        .session(&mut *session)
        .await?;
    collection_two
        .insert_one(doc! { "xyz": 999 })
        .session(session)
        .await?;

    Ok(())
}

// Step 2: Start a client session.
let mut session = client.start_session().await?;

// Step 3: Use and_run2 to start a transaction, execute the callback, and commit (or
// abort on error).
session.start_transaction().and_run2(callback).await?;

```

This example highlights the key components of the transactions API. In particular, it uses the callback API. The callback API:

- starts a transaction

- executes the specified operations

- commits the result or ends the transaction on error

Errors in server-side operations, such as the `DuplicateKeyError`, can end the transaction and result in a command error to alert the user that the transaction has ended. This behavior is expected and occurs even if the client never calls [`Session.abortTransaction()`](https://www.mongodb.com/docs/manual/reference/method/Session.abortTransaction.md#mongodb-method-Session.abortTransaction). To incorporate custom error handling, use the [Core API](https://www.mongodb.com/docs/manual/core/transactions-in-applications.md#std-label-txn-core-api) on your transaction.

The callback API incorporates retry logic for certain errors. The driver tries to rerun the transaction after a [TransientTransactionError](https://www.mongodb.com/docs/manual/core/transactions-in-applications.md#std-label-transient-transaction-error) or [UnknownTransactionCommitResult](https://www.mongodb.com/docs/manual/core/transactions-in-applications.md#std-label-unknown-transaction-commit-result) commit error.

Starting in MongoDB 6.2, the server does not retry the transaction if it receives a [TransactionTooLargeForCache](https://www.mongodb.com/docs/manual/core/transactions-in-applications.md#std-label-transactionTooLargeForCache-error) error.

Starting in MongoDB 8.1, if an `upsert` operation runs in a multidocument transaction, then the `upsert` does not retry when it encounters a duplicate key error.

**Important:**

- Use the MongoDB driver for your MongoDB version.

- When using drivers, each operation in the transaction must pass the session to each operation.

- Operations in a transaction use [transaction-level read concern](https://www.mongodb.com/docs/manual/core/transactions.md#std-label-transactions-read-concern), [transaction-level write concern](https://www.mongodb.com/docs/manual/core/transactions.md#std-label-transactions-write-concern), and [transaction-level read preference.](https://www.mongodb.com/docs/manual/core/transactions.md#std-label-transactions-read-preference)

- You can create collections in transactions implicitly or explicitly. See [Create Collections and Indexes in a Transaction.](https://www.mongodb.com/docs/manual/core/transactions.md#std-label-transactions-create-collections-indexes)

```go

// WithTransactionExample is an example of using the Session.WithTransaction function.
func WithTransactionExample(ctx context.Context) error {
	// For a replica set, include the replica set name and a seedlist of the members in the URI string; e.g.
	// uri := "mongodb://mongodb0.example.com:27017,mongodb1.example.com:27017/?replicaSet=myRepl"
	// For a sharded cluster, connect to the mongos instances; e.g.
	// uri := "mongodb://mongos0.example.com:27017,mongos1.example.com:27017/"
	uri := mtest.ClusterURI()

	clientOpts := options.Client().ApplyURI(uri)
	client, err := mongo.Connect(clientOpts)
	if err != nil {
		return err
	}
	defer func() { _ = client.Disconnect(ctx) }()

	// Prereq: Create collections.
	wcMajority := writeconcern.Majority()
	wcMajorityCollectionOpts := options.Collection().SetWriteConcern(wcMajority)
	fooColl := client.Database("mydb1").Collection("foo", wcMajorityCollectionOpts)
	barColl := client.Database("mydb1").Collection("bar", wcMajorityCollectionOpts)

	// Step 1: Define the callback that specifies the sequence of operations to perform inside the transaction.
	callback := func(sesctx context.Context) (any, error) {
		// Important: You must pass sesctx as the Context parameter to the operations for them to be executed in the
		// transaction.
		if _, err := fooColl.InsertOne(sesctx, bson.D{{"abc", 1}}); err != nil {
			return nil, err
		}
		if _, err := barColl.InsertOne(sesctx, bson.D{{"xyz", 999}}); err != nil {
			return nil, err
		}

		return nil, nil
	}

	// Step 2: Start a session and run the callback using WithTransaction.
	session, err := client.StartSession()
	if err != nil {
		return err
	}
	defer session.EndSession(ctx)

	result, err := session.WithTransaction(ctx, callback)
	if err != nil {
		return err
	}
	log.Printf("result: %v\n", result)
	return nil
}

```

This example uses the [core API](https://www.mongodb.com/docs/manual/core/transactions-in-applications.md#std-label-txn-core-api). Because the core API does not incorporate retry logic for the [`TransientTransactionError`](https://www.mongodb.com/docs/manual/core/transactions-in-applications.md#std-label-transient-transaction-error) or [`UnknownTransactionCommitResult`](https://www.mongodb.com/docs/manual/core/transactions-in-applications.md#std-label-unknown-transaction-commit-result) commit errors, the example includes explicit logic to retry the transaction for these errors:

**Note:**

When possible, use the [callback API](https://www.mongodb.com/docs/manual/core/transactions-in-applications.md#std-label-txn-callback-api), which incorporates automatic retry logic.

**Important:**

- Use the MongoDB driver for your MongoDB version.

- When using drivers, each operation in the transaction must pass the session to each operation.

- Operations in a transaction use [transaction-level read concern](https://www.mongodb.com/docs/manual/core/transactions.md#std-label-transactions-read-concern), [transaction-level write concern](https://www.mongodb.com/docs/manual/core/transactions.md#std-label-transactions-write-concern), and [transaction-level read preference.](https://www.mongodb.com/docs/manual/core/transactions.md#std-label-transactions-read-preference)

- You can create collections in transactions implicitly or explicitly. See [Create Collections and Indexes in a Transaction.](https://www.mongodb.com/docs/manual/core/transactions.md#std-label-transactions-create-collections-indexes)

```scala
/*
 * Copyright 2008-present MongoDB, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.mongodb.scala

import org.mongodb.scala.model.{Filters, Updates}
import org.mongodb.scala.result.UpdateResult

import scala.concurrent.Await
import scala.concurrent.duration.Duration


//scalastyle:off magic.number
class DocumentationTransactionsExampleSpec extends RequiresMongoDBISpec {

  // Implicit functions that execute the Observable and return the results
  val waitDuration = Duration(5, "seconds")
  implicit class ObservableExecutor[T](observable: Observable[T]) {
    def execute(): Seq[T] = Await.result(observable.toFuture(), waitDuration)
  }

  implicit class SingleObservableExecutor[T](observable: SingleObservable[T]) {
    def execute(): T = Await.result(observable.toFuture(), waitDuration)
  }
  // end implicit functions

  "The Scala driver" should "be able to commit a transaction" in withClient { client =>
    assume(serverVersionAtLeast(List(4, 0, 0)) && !hasSingleHost())
    client.getDatabase("hr").drop().execute()
    client.getDatabase("hr").createCollection("employees").execute()
    client.getDatabase("hr").createCollection("events").execute()

    updateEmployeeInfoWithRetry(client).execute() should equal(Completed())
    client.getDatabase("hr").drop().execute() should equal(Completed())
  }

  def updateEmployeeInfo(database: MongoDatabase, observable: SingleObservable[ClientSession]): SingleObservable[ClientSession] = {
    observable.map(clientSession => {
      val employeesCollection = database.getCollection("employees")
      val eventsCollection = database.getCollection("events")

      val transactionOptions = TransactionOptions.builder()
        .readPreference(ReadPreference.primary())
        .readConcern(ReadConcern.SNAPSHOT)
        .writeConcern(WriteConcern.MAJORITY)
        .build()
      clientSession.startTransaction(transactionOptions)
      employeesCollection.updateOne(clientSession, Filters.eq("employee", 3), Updates.set("status", "Inactive"))
        .subscribe((res: UpdateResult) => println(res))
      eventsCollection.insertOne(clientSession, Document("employee" -> 3, "status" -> Document("new" -> "Inactive", "old" -> "Active")))
        .subscribe((res: Completed) => println(res))

      clientSession
    })
  }

  def commitAndRetry(observable: SingleObservable[Completed]): SingleObservable[Completed] = {
    observable.recoverWith({
      case e: MongoException if e.hasErrorLabel(MongoException.UNKNOWN_TRANSACTION_COMMIT_RESULT_LABEL) => {
        println("UnknownTransactionCommitResult, retrying commit operation ...")
        commitAndRetry(observable)
      }
      case e: Exception => {
        println(s"Exception during commit ...: $e")
        throw e
      }
    })
  }

  def runTransactionAndRetry(observable: SingleObservable[Completed]): SingleObservable[Completed] = {
    observable.recoverWith({
      case e: MongoException if e.hasErrorLabel(MongoException.TRANSIENT_TRANSACTION_ERROR_LABEL) => {
        println("TransientTransactionError, aborting transaction and retrying ...")
        runTransactionAndRetry(observable)
      }
    })
  }

  def updateEmployeeInfoWithRetry(client: MongoClient): SingleObservable[Completed] = {

    val database = client.getDatabase("hr")
    val updateEmployeeInfoObservable: Observable[ClientSession] = updateEmployeeInfo(database, client.startSession())
    val commitTransactionObservable: SingleObservable[Completed] =
      updateEmployeeInfoObservable.flatMap(clientSession => clientSession.commitTransaction())
    val commitAndRetryObservable: SingleObservable[Completed] = commitAndRetry(commitTransactionObservable)

    runTransactionAndRetry(commitAndRetryObservable)
  }
}

```

**See also:**

For an example in [`mongosh`](https://www.mongodb.com/docs/mongodb-shell.md#mongodb-binary-bin.mongosh), see [`mongosh` Example.](https://www.mongodb.com/docs/manual/core/transactions-in-applications.md#std-label-txn-mongo-shell-example)

## Transactions and Atomicity

For situations that require atomicity of reads and writes to multiple documents (in a single or multiple collections), MongoDB supports distributed transactions, including transactions on replica sets and sharded clusters.

Distributed transactions are atomic:

- Transactions either apply all data changes or roll back the changes.

- If a transaction commits, all data changes made in the transaction are saved and are visible outside of the transaction.

  Until a transaction commits, the data changes made in the transaction are not visible outside the transaction.

  However, when a transaction writes to multiple shards, not all outside read operations need to wait for the result of the committed transaction to be visible across the shards. For example, if a transaction is committed and write 1 is visible on shard A but write 2 is not yet visible on shard B, an outside read at read concern [`"local"`](https://www.mongodb.com/docs/manual/reference/read-concern-local.md#mongodb-readconcern-readconcern.-local-) can read the results of write 1 without seeing write 2.

- When a transaction aborts, all data changes made in the transaction are discarded without ever becoming visible.

**Important:**

In most cases, a distributed transaction incurs a greater performance cost over single document writes, and the availability of distributed transactions should not be a replacement for effective schema design. For many scenarios, the [denormalized data model (embedded documents and arrays)](https://www.mongodb.com/docs/manual/data-modeling/embedding.md#std-label-data-modeling-embedding) will continue to be optimal for your data and use cases. That is, for many scenarios, modeling your data appropriately will minimize the need for distributed transactions.

For additional transactions usage considerations (such as runtime limit and oplog size limit), see also [Production Considerations.](https://www.mongodb.com/docs/manual/core/transactions-production-consideration.md#std-label-production-considerations)

**See also:**

[Outside Reads During Commit](https://www.mongodb.com/docs/manual/core/transactions-production-consideration.md#std-label-transactions-prod-consideration-outside-reads)

## Transactions and Operations

Transactions can be used across multiple operations, collections, databases, documents, and shards.

For transactions:

- You can create collections and indexes in transactions. For details, see [Create Collections and Indexes in a Transaction](https://www.mongodb.com/docs/manual/core/transactions.md#std-label-transactions-create-collections-indexes)

- The collections used in a transaction can be in different databases.

  **Note:**

  You cannot create new collections in cross-shard write transactions. For example, if you write to an existing collection in one shard and implicitly create a collection in a different shard, MongoDB cannot perform both operations in the same transaction.

- You cannot write to [capped](https://www.mongodb.com/docs/manual/core/capped-collections.md#std-label-manual-capped-collection) collections.

- You cannot use read concern [`"snapshot"`](https://www.mongodb.com/docs/manual/reference/read-concern-snapshot.md#mongodb-readconcern-readconcern.-snapshot-) when reading from a [capped](https://www.mongodb.com/docs/manual/core/capped-collections.md#std-label-manual-capped-collection) collection. (Starting in MongoDB 5.0)

- You cannot read/write to collections in the `config`, `admin`, or `local` databases.

- You cannot write to `system.*` collections.

- You cannot return the supported operation's query plan using `explain` or similar commands.

* For cursors created outside of a transaction, you cannot call [`getMore`](https://www.mongodb.com/docs/manual/reference/command/getMore.md#mongodb-dbcommand-dbcmd.getMore) inside the transaction.

* For cursors created in a transaction, you cannot call [`getMore`](https://www.mongodb.com/docs/manual/reference/command/getMore.md#mongodb-dbcommand-dbcmd.getMore) outside the transaction.

- You cannot specify the [`killCursors`](https://www.mongodb.com/docs/manual/reference/command/killCursors.md#mongodb-dbcommand-dbcmd.killCursors) command as the first operation in a [transaction.](https://www.mongodb.com/docs/manual/core/transactions.md#std-label-transactions)

  Additionally, if you run the `killCursors` command within a transaction, the server immediately stops the specified cursors. It does **not** wait for the transaction to commit.

For a list of operations not supported in transactions, see [Restricted Operations.](https://www.mongodb.com/docs/manual/core/transactions.md#std-label-transactions-ops-restricted)

**Tip:**

When creating or dropping a collection immediately before starting a transaction, if the collection is accessed within the transaction, issue the create or drop operation with write concern [`"majority"`](https://www.mongodb.com/docs/manual/reference/write-concern.md#mongodb-writeconcern-writeconcern.-majority-) to ensure that the transaction can acquire the required locks.

**See also:**

[Transactions and Operations Reference](https://www.mongodb.com/docs/manual/core/transactions-operations.md#std-label-transactions-operations-ref)

### Create Collections and Indexes in a Transaction

You can perform the following operations in a [transaction](https://www.mongodb.com/docs/manual/core/transactions.md#std-label-transactions) if it is not a cross-shard write transaction:

- Create collections.

- Create indexes on new empty collections created earlier in the same transaction.

When creating a collection inside a transaction:

- You can [implicitly create a collection](https://www.mongodb.com/docs/manual/core/transactions-operations.md#std-label-transactions-operations-ddl-implicit), such as with:

  - an [insert operation](https://www.mongodb.com/docs/manual/core/transactions-operations.md#std-label-transactions-operations-ddl-implicit) for a non-existent collection, or

  - an [update/findAndModify operation](https://www.mongodb.com/docs/manual/core/transactions-operations.md#std-label-transactions-operations-ddl-implicit) with `upsert: true` for a non-existent collection.

- You can [explicitly create a collection](https://www.mongodb.com/docs/manual/core/transactions-operations.md#std-label-transactions-operations-ddl-explicit) using the [`create`](https://www.mongodb.com/docs/manual/reference/command/create.md#mongodb-dbcommand-dbcmd.create) command or its helper [`db.createCollection()`.](https://www.mongodb.com/docs/manual/reference/method/db.createCollection.md#mongodb-method-db.createCollection)

When [creating an index inside a transaction](https://www.mongodb.com/docs/manual/core/transactions-operations.md#std-label-transactions-operations-ddl-explicit) , the index to create must be on either:

- a non-existent collection. The collection is created as part of the operation.

- a new empty collection created earlier in the same transaction.

You can also run [`db.collection.createIndex()`](https://www.mongodb.com/docs/manual/reference/method/db.collection.createIndex.md#mongodb-method-db.collection.createIndex) and [`db.collection.createIndexes()`](https://www.mongodb.com/docs/manual/reference/method/db.collection.createIndexes.md#mongodb-method-db.collection.createIndexes) on existing indexes to check for existence. These operations return successfully without creating the index.

#### Restrictions

- You cannot create new collections in cross-shard write transactions. For example, if you write to an existing collection in one shard and implicitly create a collection in a different shard, MongoDB cannot perform both operations in the same transaction.

- You **cannot** use the `$graphLookup` stage within a transaction while targeting a sharded collection.

- For explicit creation of a collection or an index inside a transaction, the transaction read concern level must be [`"local"`.](https://www.mongodb.com/docs/manual/reference/read-concern-local.md#mongodb-readconcern-readconcern.-local-)

  To explicitly create collections and indexes, use the following commands and methods:

  | Command | Method |
  | --- | --- |
  | [`create`](https://www.mongodb.com/docs/manual/reference/command/create.md#mongodb-dbcommand-dbcmd.create) | [`db.createCollection()`](https://www.mongodb.com/docs/manual/reference/method/db.createCollection.md#mongodb-method-db.createCollection) |
  | [`createIndexes`](https://www.mongodb.com/docs/manual/reference/command/createIndexes.md#mongodb-dbcommand-dbcmd.createIndexes) | [`db.collection.createIndex()`](https://www.mongodb.com/docs/manual/reference/method/db.collection.createIndex.md#mongodb-method-db.collection.createIndex)[`db.collection.createIndexes()`](https://www.mongodb.com/docs/manual/reference/method/db.collection.createIndexes.md#mongodb-method-db.collection.createIndexes) |

**See also:**

[Restricted Operations](https://www.mongodb.com/docs/manual/core/transactions.md#std-label-transactions-ops-restricted)

### Count Operation

To perform a count operation within a transaction, use the [`$count`](https://www.mongodb.com/docs/manual/reference/operator/aggregation/count.md#mongodb-pipeline-pipe.-count) aggregation stage or the [`$group`](https://www.mongodb.com/docs/manual/reference/operator/aggregation/group.md#mongodb-pipeline-pipe.-group) (with a [`$sum`](https://www.mongodb.com/docs/manual/reference/operator/aggregation/sum.md#mongodb-group-grp.-sum) expression) aggregation stage.

MongoDB drivers provide a collection-level API `countDocuments(filter, options)` as a helper method that uses the [`$group`](https://www.mongodb.com/docs/manual/reference/operator/aggregation/group.md#mongodb-pipeline-pipe.-group) with a [`$sum`](https://www.mongodb.com/docs/manual/reference/operator/aggregation/sum.md#mongodb-group-grp.-sum) expression to perform a count.

[`mongosh`](https://www.mongodb.com/docs/mongodb-shell.md#mongodb-binary-bin.mongosh) provides the [`db.collection.countDocuments()`](https://www.mongodb.com/docs/manual/reference/method/db.collection.countDocuments.md#mongodb-method-db.collection.countDocuments) helper method that uses the [`$group`](https://www.mongodb.com/docs/manual/reference/operator/aggregation/group.md#mongodb-pipeline-pipe.-group) with a [`$sum`](https://www.mongodb.com/docs/manual/reference/operator/aggregation/sum.md#mongodb-group-grp.-sum) expression to perform a count.

### Distinct Operation

To perform a distinct operation within a transaction:

- For unsharded collections, you can use the [`db.collection.distinct()`](https://www.mongodb.com/docs/manual/reference/method/db.collection.distinct.md#mongodb-method-db.collection.distinct) method/the [`distinct`](https://www.mongodb.com/docs/manual/reference/command/distinct.md#mongodb-dbcommand-dbcmd.distinct) command as well as the aggregation pipeline with the [`$group`](https://www.mongodb.com/docs/manual/reference/operator/aggregation/group.md#mongodb-pipeline-pipe.-group) stage.

- For sharded collections, you cannot use the [`db.collection.distinct()`](https://www.mongodb.com/docs/manual/reference/method/db.collection.distinct.md#mongodb-method-db.collection.distinct) method or the [`distinct`](https://www.mongodb.com/docs/manual/reference/command/distinct.md#mongodb-dbcommand-dbcmd.distinct) command.

  To find the distinct values for a sharded collection, use the aggregation pipeline with the [`$group`](https://www.mongodb.com/docs/manual/reference/operator/aggregation/group.md#mongodb-pipeline-pipe.-group) stage instead. For example:

  - Instead of `db.coll.distinct("x")`, use

    ```javascript
    db.coll.aggregate([
       { $group: { _id: null, distinctValues: { $addToSet: "$x" } } },
       { $project: { _id: 0 } }
    ])
    ```

  - Instead of `db.coll.distinct("x", { status: "A" })`, use:

    ```javascript
    db.coll.aggregate([
       { $match: { status: "A" } },
       { $group: { _id: null, distinctValues: { $addToSet: "$x" } } },
       { $project: { _id: 0 } }
    ])
    ```

  The pipeline returns a cursor to a document:

  ```javascript
  { "distinctValues" : [ 2, 3, 1 ] }
  ```

  Iterate the cursor to access the results document.

### Informational Operations

Informational commands, such as [`hello`](https://www.mongodb.com/docs/manual/reference/command/hello.md#mongodb-dbcommand-dbcmd.hello), [`buildInfo`](https://www.mongodb.com/docs/manual/reference/command/buildInfo.md#mongodb-dbcommand-dbcmd.buildInfo), [`connectionStatus`](https://www.mongodb.com/docs/manual/reference/command/connectionStatus.md#mongodb-dbcommand-dbcmd.connectionStatus) (and their helper methods) are allowed in transactions; however, they cannot be the first operation in the transaction.

### Restricted Operations

The following operations are not allowed in transactions:

- Creating new collections in cross-shard write transactions. For example, if you write to an existing collection in one shard and implicitly create a collection in a different shard, MongoDB cannot perform both operations in the same transaction.

- [Explicit creation of collections](https://www.mongodb.com/docs/manual/core/transactions-operations.md#std-label-transactions-operations-ddl-explicit), e.g. [`db.createCollection()`](https://www.mongodb.com/docs/manual/reference/method/db.createCollection.md#mongodb-method-db.createCollection) method, and indexes, e.g. [`db.collection.createIndexes()`](https://www.mongodb.com/docs/manual/reference/method/db.collection.createIndexes.md#mongodb-method-db.collection.createIndexes) and [`db.collection.createIndex()`](https://www.mongodb.com/docs/manual/reference/method/db.collection.createIndex.md#mongodb-method-db.collection.createIndex) methods, when using a read concern level other than [`"local"`.](https://www.mongodb.com/docs/manual/reference/read-concern-local.md#mongodb-readconcern-readconcern.-local-)

- The [`listCollections`](https://www.mongodb.com/docs/manual/reference/command/listCollections.md#mongodb-dbcommand-dbcmd.listCollections) and [`listIndexes`](https://www.mongodb.com/docs/manual/reference/command/listIndexes.md#mongodb-dbcommand-dbcmd.listIndexes) commands and their helper methods.

- Other non-CRUD and non-informational operations, such as [`createUser`](https://www.mongodb.com/docs/manual/reference/command/createUser.md#mongodb-dbcommand-dbcmd.createUser), [`getParameter`](https://www.mongodb.com/docs/manual/reference/command/getParameter.md#mongodb-dbcommand-dbcmd.getParameter), [`count`](https://www.mongodb.com/docs/manual/reference/command/count.md#mongodb-dbcommand-dbcmd.count), etc. and their helpers.

- Parallel operations. To update multiple namespaces concurrently, consider using the [`bulkWrite`](https://www.mongodb.com/docs/manual/reference/command/bulkWrite.md#mongodb-dbcommand-dbcmd.bulkWrite) command instead.

**See also:**

- [Pending DDL Operations and Transactions](https://www.mongodb.com/docs/manual/core/transactions-production-consideration.md#std-label-txn-prod-considerations-ddl)

- [Transactions and Operations Reference](https://www.mongodb.com/docs/manual/core/transactions-operations.md#std-label-transactions-operations-ref)

## Transactions and Sessions

- Transactions are associated with a session.

- You can have at most one open transaction at a time for a session.

- When using the drivers, each operation in the transaction must be associated with the session. Refer to your driver specific documentation for details.

- If a session ends and it has an open transaction, the transaction aborts.

## Read Concern, Write Concern, and Read Preference

### Transactions and Read Preference

Operations in a transaction use the transaction-level [read preference.](https://www.mongodb.com/docs/manual/core/read-preference.md#std-label-replica-set-read-preference)

Using the drivers, you can set the transaction-level [read preference](https://www.mongodb.com/docs/manual/core/read-preference.md#std-label-replica-set-read-preference) at the transaction start:

- If the transaction-level read preference is unset, the transaction uses the session-level read preference.

- If transaction-level and the session-level read preference are unset, the transaction uses the client-level read preference. By default, the client-level read preference is [`primary`.](https://www.mongodb.com/docs/manual/reference/glossary.md#std-term-primary)

[Transactions](https://www.mongodb.com/docs/manual/core/transactions.md#std-label-transactions) that contain read operations must use read preference [`primary`](https://www.mongodb.com/docs/manual/reference/glossary.md#std-term-primary). All operations in a given transaction must route to the same member.

### Transactions and Read Concern

Operations in a transaction use the transaction-level [read concern](https://www.mongodb.com/docs/manual/reference/read-concern.md#std-label-read-concern). This means a read concern set at the collection and database level is ignored inside the transaction.

You can set the transaction-level [read concern](https://www.mongodb.com/docs/manual/reference/read-concern.md#std-label-read-concern) at the transaction start.

- If the transaction-level read concern is unset, the transaction-level read concern defaults to the session-level read concern.

- If transaction-level and the session-level read concern are unset, the transaction-level read concern defaults to the client-level read concern. By default, the client-level read concern is [`"local"`](https://www.mongodb.com/docs/manual/reference/read-concern-local.md#mongodb-readconcern-readconcern.-local-) for reads on the primary. See also:

  - [Transactions and Read Preference](https://www.mongodb.com/docs/manual/core/transactions.md#std-label-transactions-read-preference)

  - [MongoDB Defaults](https://www.mongodb.com/docs/manual/reference/mongodb-defaults.md#std-label-default-mongodb-read-write-concerns)

Transactions support the following read concern levels:

#### `"local"`

- Read concern [`"local"`](https://www.mongodb.com/docs/manual/reference/read-concern-local.md#mongodb-readconcern-readconcern.-local-) returns the most recent data available from the node but can be rolled back.

- On a replica set, even if a transaction uses read concern `local`, you might observe stronger read isolation where the operation reads from a snapshot at the point in time that the transaction was opened.

- For transactions on sharded cluster, [`"local"`](https://www.mongodb.com/docs/manual/reference/read-concern-local.md#mongodb-readconcern-readconcern.-local-) read concern cannot guarantee that the data is from the same snapshot view across the shards. If snapshot isolation is required, use [`"snapshot"`](https://www.mongodb.com/docs/manual/core/transactions.md#std-label-transactions-read-concern-snapshot) read concern.

- You can [create collections and indexes](https://www.mongodb.com/docs/manual/core/transactions.md#std-label-transactions-create-collections-indexes) inside a transaction. If [explicitly](https://www.mongodb.com/docs/manual/core/transactions-operations.md#std-label-transactions-operations-ddl-explicit) creating a collection or an index, the transaction must use read concern [`"local"`](https://www.mongodb.com/docs/manual/reference/read-concern-local.md#mongodb-readconcern-readconcern.-local-). If you [implicitly](https://www.mongodb.com/docs/manual/core/transactions-operations.md#std-label-transactions-operations-ddl-implicit) create a collection, you can use any of the read concerns available for transactions.

#### `"majority"`

- If the transaction commits with [write concern "majority"](https://www.mongodb.com/docs/manual/core/transactions.md#std-label-transactions-write-concern), read concern [`"majority"`](https://www.mongodb.com/docs/manual/reference/read-concern-majority.md#mongodb-readconcern-readconcern.-majority-) returns data that has been acknowledged by a majority of the replica set members and can't be rolled back. Otherwise, read concern [`"majority"`](https://www.mongodb.com/docs/manual/reference/read-concern-majority.md#mongodb-readconcern-readconcern.-majority-) provides no guarantees that read operations read majority-committed data.

- For transactions on sharded cluster, read concern [`"majority"`](https://www.mongodb.com/docs/manual/reference/read-concern-majority.md#mongodb-readconcern-readconcern.-majority-) can't guarantee that the data is from the same snapshot view across the shards. If snapshot isolation is required, use read concern [`"snapshot"`.](https://www.mongodb.com/docs/manual/core/transactions.md#std-label-transactions-read-concern-snapshot)

#### `"snapshot"`

- Read concern [`"snapshot"`](https://www.mongodb.com/docs/manual/reference/read-concern-snapshot.md#mongodb-readconcern-readconcern.-snapshot-) returns data from a snapshot of majority committed data **if** the transaction commits with [write concern "majority".](https://www.mongodb.com/docs/manual/core/transactions.md#std-label-transactions-write-concern)

- If the transaction does not use [write concern "majority"](https://www.mongodb.com/docs/manual/core/transactions.md#std-label-transactions-write-concern) for the commit, the [`"snapshot"`](https://www.mongodb.com/docs/manual/reference/read-concern-snapshot.md#mongodb-readconcern-readconcern.-snapshot-) read concern provides **no** guarantee that read operations used a snapshot of majority-committed data.

- For transactions on sharded clusters, the [`"snapshot"`](https://www.mongodb.com/docs/manual/reference/read-concern-snapshot.md#mongodb-readconcern-readconcern.-snapshot-) view of the data **is** synchronized across shards.

### Transactions and Write Concern

Transactions use the transaction-level [write concern](https://www.mongodb.com/docs/manual/reference/write-concern.md#std-label-write-concern) to commit the write operations. Write operations inside transactions must be run without an explicit write concern specification and use the default write concern. At commit time, the writes are committed using the transaction-level write concern.

**Tip:**

Don't explicitly set the write concern for the individual write operations inside a transaction. Setting write concerns for the individual write operations inside a transaction returns an error.

You can set the transaction-level [write concern](https://www.mongodb.com/docs/manual/reference/write-concern.md#std-label-write-concern) at the transaction start:

- If the transaction-level write concern is unset, the transaction-level write concern defaults to the session-level write concern for the commit.

- If the transaction-level write concern and the session-level write concern are unset, the transaction-level write concern defaults to the client-level write concern of:

  - [`w: "majority"`](https://www.mongodb.com/docs/manual/reference/write-concern.md#mongodb-writeconcern-writeconcern.-majority-) in MongoDB 5.0 and later, with differences for deployments containing [arbiters](https://www.mongodb.com/docs/manual/core/replica-set-arbiter.md#std-label-replica-set-arbiter-configuration). See [Implicit Default Write Concern.](https://www.mongodb.com/docs/manual/reference/write-concern.md#std-label-wc-default-behavior)

  - [`w: 1`](https://www.mongodb.com/docs/manual/reference/write-concern.md#mongodb-writeconcern-writeconcern.-number-)

**See also:**

[MongoDB Defaults](https://www.mongodb.com/docs/manual/reference/mongodb-defaults.md#std-label-default-mongodb-read-write-concerns)

Transactions support all write concern [w](https://www.mongodb.com/docs/manual/reference/write-concern.md#std-label-wc-w) values, including:

#### `w: 1`

- Write concern [`w: 1`](https://www.mongodb.com/docs/manual/reference/write-concern.md#mongodb-writeconcern-writeconcern.-number-) returns acknowledgment after the commit has been applied to the primary.

  **Important:**

  When you commit with [`w: 1`](https://www.mongodb.com/docs/manual/reference/write-concern.md#mongodb-writeconcern-writeconcern.-number-), your transaction can be [rolled back if there is a failover.](https://www.mongodb.com/docs/manual/core/replica-set-rollbacks.md#std-label-replica-set-rollbacks)

- When you commit with [`w: 1`](https://www.mongodb.com/docs/manual/reference/write-concern.md#mongodb-writeconcern-writeconcern.-number-) write concern, transaction-level [`"majority"`](https://www.mongodb.com/docs/manual/reference/read-concern-majority.md#mongodb-readconcern-readconcern.-majority-) read concern provides **no** guarantees that read operations in the transaction read majority-committed data.

- When you commit with [`w: 1`](https://www.mongodb.com/docs/manual/reference/write-concern.md#mongodb-writeconcern-writeconcern.-number-) write concern, transaction-level [`"snapshot"`](https://www.mongodb.com/docs/manual/reference/read-concern-snapshot.md#mongodb-readconcern-readconcern.-snapshot-) read concern provides **no** guarantee that read operations in the transaction used a snapshot of majority-committed data.

#### `w: "majority"`

- Write concern [`w: "majority"`](https://www.mongodb.com/docs/manual/reference/write-concern.md#mongodb-writeconcern-writeconcern.-majority-) returns acknowledgment after the commit has been applied to a majority of voting members.

- When you commit with [`w: "majority"`](https://www.mongodb.com/docs/manual/reference/write-concern.md#mongodb-writeconcern-writeconcern.-majority-) write concern, transaction-level [`"majority"`](https://www.mongodb.com/docs/manual/reference/read-concern-majority.md#mongodb-readconcern-readconcern.-majority-) read concern guarantees that operations have read majority-committed data. For transactions on sharded clusters, this view of the majority-committed data is not synchronized across shards.

- When you commit with [`w: "majority"`](https://www.mongodb.com/docs/manual/reference/write-concern.md#mongodb-writeconcern-writeconcern.-majority-) write concern, transaction-level [`"snapshot"`](https://www.mongodb.com/docs/manual/reference/read-concern-snapshot.md#mongodb-readconcern-readconcern.-snapshot-) read concern guarantees that operations have read from a synchronized snapshot of majority-committed data.

**Note:**

Regardless of the [write concern specified for the transaction](https://www.mongodb.com/docs/manual/core/transactions.md#std-label-transactions-write-concern), the commit operation for a sharded cluster transaction includes some parts that use `{w:
  "majority", j: true}` write concern.

The server parameter [`coordinateCommitReturnImmediatelyAfterPersistingDecision`](https://www.mongodb.com/docs/manual/reference/parameters.md#mongodb-parameter-param.coordinateCommitReturnImmediatelyAfterPersistingDecision) controls when transaction commit decisions are returned to the client.

The parameter was introduced in MongDB 5.0 with a default value of `true`. In MongoDB 6.1 the default value changes to `false`.

When `coordinateCommitReturnImmediatelyAfterPersistingDecision` is `false`, the [shard](https://www.mongodb.com/docs/manual/core/sharded-cluster-shards.md#std-label-shards-concepts) transaction coordinator waits for all members to acknowledge a [transaction](https://www.mongodb.com/docs/manual/core/transactions.md#std-label-transactions-atomicity) commit before returning the commit decision to the client.

If you specify a [`"majority"`](https://www.mongodb.com/docs/manual/reference/write-concern.md#mongodb-writeconcern-writeconcern.-majority-) write concern for writes and the operation does not replicate to the  [calculated majority](https://www.mongodb.com/docs/manual/reference/write-concern.md#std-label-calculating-majority-count) of [replica set](https://www.mongodb.com/docs/manual/reference/glossary.md#std-term-replica-set) members before it returns a response, then the data eventually replicates or rolls back. See [`wtimeout`.](https://www.mongodb.com/docs/manual/reference/write-concern.md#std-label-wc-wtimeout)

Regardless of the [write concern specified for the transaction](https://www.mongodb.com/docs/manual/core/transactions.md#std-label-transactions-write-concern), the driver applies [`w: "majority"`](https://www.mongodb.com/docs/manual/reference/write-concern.md#mongodb-writeconcern-writeconcern.-majority-) as the write concern when retrying [`commitTransaction`.](https://www.mongodb.com/docs/manual/reference/command/commitTransaction.md#mongodb-dbcommand-dbcmd.commitTransaction)

## Transactions Considerations

The following sections describe transaction requirements and considerations that vary by deployment type, storage engine, and MongoDB version.

### Production Considerations

For transactions in production environments, see [Production Considerations](https://www.mongodb.com/docs/manual/core/transactions-production-consideration.md#std-label-production-considerations). In addition, for sharded clusters, see [Production Considerations (Sharded Clusters).](https://www.mongodb.com/docs/manual/core/transactions-sharded-clusters.md#std-label-production-considerations-sharded)

### Arbiters

Since arbiters are voting replicas that don't contain data, MongoDB protects your data and prevents multi-shard data transactions from targeting shards whose replica sets include an arbiter. This includes changing a [shard key](https://www.mongodb.com/docs/manual/reference/glossary.md#std-term-shard-key) using a transaction.

MongoDB blocks transactions whose write operations span multiple shards if any transaction operation reads from or writes to a shard that contains an arbiter.

### Shard Configuration Restriction

To run transactions on a sharded cluster, [`writeConcernMajorityJournalDefault`](https://www.mongodb.com/docs/manual/reference/replica-configuration.md#mongodb-rsconf-rsconf.writeConcernMajorityJournalDefault) must be set to `true`.

**Note:**

Regardless of the [write concern specified for the transaction](https://www.mongodb.com/docs/manual/core/transactions.md#std-label-transactions-write-concern), the commit operation for a sharded cluster transaction includes some parts that use `{w:
  "majority", j: true}` write concern.

### Diagnostics

To obtain transaction status and metrics, use the following methods:

| Source | Returns |
| --- | --- |
| [`db.serverStatus()`](https://www.mongodb.com/docs/manual/reference/method/db.serverStatus.md#mongodb-method-db.serverStatus) method[`serverStatus`](https://www.mongodb.com/docs/manual/reference/command/serverStatus.md#mongodb-dbcommand-dbcmd.serverStatus) command | Returns [transactions](https://www.mongodb.com/docs/manual/reference/command/serverStatus.md#std-label-server-status-transactions) metrics. Some `serverStatus` response fields are not returned on MongoDB Atlas Free clusters or Flex clusters. For more information, see [Limited Commands](https://www.mongodb.com/docs/atlas/unsupported-commands.md#std-label-free-shard-commands-with-limits) in the MongoDB Atlas documentation. |
| [`$currentOp`](https://www.mongodb.com/docs/manual/reference/operator/aggregation/currentOp.md#mongodb-pipeline-pipe.-currentOp) aggregation pipeline | Returns: [`$currentOp.transaction`](https://www.mongodb.com/docs/manual/reference/operator/aggregation/currentOp.md#mongodb-data--currentOp.transaction) if an operation is part of a transaction.; Information on [inactive sessions](https://www.mongodb.com/docs/manual/reference/operator/aggregation/currentOp.md#std-label-currentOp-stage-idleSessions) that are holding locks as part of a transaction.; [`$currentOp.twoPhaseCommitCoordinator`](https://www.mongodb.com/docs/manual/reference/operator/aggregation/currentOp.md#mongodb-data--currentOp.twoPhaseCommitCoordinator) metrics for sharded transactions that involves writes to multiple shards. |
| [`db.currentOp()`](https://www.mongodb.com/docs/manual/reference/method/db.currentOp.md#mongodb-method-db.currentOp) method[`currentOp`](https://www.mongodb.com/docs/manual/reference/command/currentOp.md#mongodb-dbcommand-dbcmd.currentOp) command | Returns: [`currentOp.transaction`](https://www.mongodb.com/docs/manual/reference/command/currentOp.md#mongodb-data-currentOp.transaction) if an operation is part of a transaction.; [`currentOp.twoPhaseCommitCoordinator`](https://www.mongodb.com/docs/manual/reference/command/currentOp.md#mongodb-data-currentOp.twoPhaseCommitCoordinator) metrics for sharded transactions that involves writes to multiple shards. |
| [`mongod`](https://www.mongodb.com/docs/manual/reference/program/mongod.md#mongodb-binary-bin.mongod) and [`mongos`](https://www.mongodb.com/docs/manual/reference/program/mongos.md#mongodb-binary-bin.mongos) log messages | Includes information on slow transactions (which are transactions that exceed the [`operationProfiling.slowOpThresholdMs`](https://www.mongodb.com/docs/manual/reference/configuration-options.md#mongodb-setting-operationProfiling.slowOpThresholdMs) threshold) in the [`TXN`](https://www.mongodb.com/docs/manual/reference/log-messages.md#mongodb-data-TXN) log component. |

### Feature Compatibility Version (FCV)

To use transactions, the [featureCompatibilityVersion](https://www.mongodb.com/docs/manual/reference/command/setFeatureCompatibilityVersion.md#std-label-view-fcv) for all members of the deployment must be at least:

| Deployment | Minimum `featureCompatibilityVersion` |
| --- | --- |
| Replica Set | `4.0` |
| Sharded Cluster | `4.2` |

To check the FCV for a member, connect to the member and run the following command:

```javascript
db.adminCommand( { getParameter: 1, featureCompatibilityVersion: 1 } )
```

For more information, see the [`setFeatureCompatibilityVersion`](https://www.mongodb.com/docs/manual/reference/command/setFeatureCompatibilityVersion.md#mongodb-dbcommand-dbcmd.setFeatureCompatibilityVersion) reference page.

### Storage Engines

[Transactions](https://www.mongodb.com/docs/manual/core/transactions.md#std-label-transactions) are supported on replica sets and sharded clusters where:

- the primary uses the WiredTiger storage engine, and

- the secondary members use either the WiredTiger storage engine or the [in-memory](https://www.mongodb.com/docs/manual/core/inmemory.md#std-label-storage-inmemory) storage engines.

**Note:**

You cannot run transactions on a sharded cluster that has a shard with [`writeConcernMajorityJournalDefault`](https://www.mongodb.com/docs/manual/reference/replica-configuration.md#mongodb-rsconf-rsconf.writeConcernMajorityJournalDefault) set to `false`, such as a shard with a voting member that uses the in-memory storage engine.

### Limit Critical Section Wait Time

Starting in MongoDB 5.2 (and 5.0.4):

- When a query accesses a shard, a [chunk migration](https://www.mongodb.com/docs/manual/tutorial/migrate-chunks-in-sharded-cluster.md#std-label-migrate-chunks-sharded-cluster) or [DDL operation](https://www.mongodb.com/docs/manual/core/transactions-operations.md#std-label-transactions-operations-ddl) may hold the critical section for the collection.

- To limit the time a shard waits for a critical section within a transaction, use the [`metadataRefreshInTransactionMaxWaitMS`](https://www.mongodb.com/docs/manual/reference/parameters.md#mongodb-parameter-param.metadataRefreshInTransactionMaxWaitMS) parameter.

  **Note:**

  Starting in MongoDB 8.1, the old `metadataRefreshInTransactionMaxWaitBehindCritSecMS` parameter is renamed `metadataRefreshInTransactionMaxWaitMS`. You can continue to use `metadataRefreshInTransactionMaxWaitBehindCritSecMS` as the parameter name, but it is deprecated and will be removed in a future MongoDB release.

## Learn More

- [Drivers API](https://www.mongodb.com/docs/manual/core/transactions-in-applications.md#std-label-transactions-drivers)

- [Production Considerations](https://www.mongodb.com/docs/manual/core/transactions-production-consideration.md#std-label-production-considerations)

- [Sharded Clusters](https://www.mongodb.com/docs/manual/core/transactions-sharded-clusters.md#std-label-production-considerations-sharded)

- [Transactions and Operations](https://www.mongodb.com/docs/manual/core/transactions-operations.md#std-label-transactions-operations-ref)
