Navigation
This is an upcoming (i.e. in progress) version of the manual.

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, this single-document atomicity obviates the need for multi-document transactions for many practical use cases.

However, for situations that require atomicity for writes to multiple documents or consistency between reads to multiple documents:

  • Starting in version 4.0, MongoDB provides the ability to perform multi-document transactions for replica sets.

  • Starting in version 4.2, MongoDB provides the ability to perform multi-document transactions for sharded clusters. For transactions on MongoDB 4.2 deployments(replica sets and sharded clusters), clients require MongoDB drivers updated for MongoDB 4.2.

    Sharded Clusters Transactions (Beta)

    To join the beta program for sharded clusters transactions, sign up at https://www.mongodb.com/transactions/globalbeta.

Multi-document transactions can be used across multiple operations, collections, databases, documents, and shards.

Important

In most cases, multi-document transaction incurs a greater performance cost over single document writes, and the availability of multi-document transaction should not be a replacement for effective schema design. For many scenarios, the denormalized data model (embedded documents and arrays) 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 multi-document transactions.

Transactions API

The API for using transactions is the same whether for a replica set or a sharded cluster.

The following example highlights the key components of the transactions API:

Note

The example uses the new callback API for working with transactions. The new callback API incorporates retry logic for TransientTransactionError or UnknownTransactionCommitResult commit errors.

# 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/admin?replicaSet=myRepl'
# For a sharded cluster, connect to the mongos instances; e.g.
# uriString = 'mongodb://mongos0.example.com:27017,mongos1.example.com:27017/admin'

client = MongoClient(uriString)

my_write_concern_majority = WriteConcern('majority', wtimeout=1000)

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

client.get_database(
    'mydb1',
    write_concern=my_write_concern_majority).foo.insert_one({'abc': 0})
client.get_database(
    'mydb2',
    write_concern=my_write_concern_majority).bar.insert_one({'xyz': 0})

def callback(my_session):
    collection_one = my_session.client.mydb1.foo
    collection_two = my_session.client.mydb2.bar
    collection_one.insert_one({'abc': 1}, session=my_session)
    collection_two.insert_one({'xyz': 999}, session=my_session)

with client.start_session() as session:
    session.with_transaction(callback,
                             read_concern=ReadConcern('local'),
                             write_concern=my_write_concern_majority,
                             read_preference=ReadPreference.PRIMARY)

Note

The example uses the new callback API for working with transactions. The new callback API incorporates retry logic for TransientTransactionError or UnknownTransactionCommitResult commit errors.

/*
  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; e.g.
  String uri = "mongodb://mongos0.example.com:27017,mongos1.example.com:27017:27017/admin";
 */

final MongoClient client = MongoClients.create(uri);

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

client.getDatabase("mydb1").getCollection("foo")
        .withWriteConcern(WriteConcern.MAJORITY).insertOne( new Document("abc", 0));
client.getDatabase("mydb2").getCollection("bar")
        .withWriteConcern(WriteConcern.MAJORITY).insertOne( new Document("xyz", 0));

final ClientSession clientSession = client.startSession();

TransactionOptions txnOptions = TransactionOptions.builder()
        .readPreference(ReadPreference.primary())
        .readConcern(ReadConcern.LOCAL)
        .writeConcern(WriteConcern.MAJORITY)
        .build();

TransactionBody txnBody = new TransactionBody<String>() {
    public String execute() {
        MongoCollection<Document> coll1 = client.getDatabase("mydb1").getCollection("foo");
        MongoCollection<Document> coll2 = client.getDatabase("mydb2").getCollection("bar");

        coll1.insertOne(new Document("abc", 1));
        coll2.insertOne(new Document("xyz", 999));

        return "Inserted into collections in different databases";
    }
};
try {
    clientSession.withTransaction(txnOptions, txnBody);
} catch (RuntimeException e) {
    // some error handling
} finally {
    clientSession.close();
}

Note

The mongo shell example omits retry logic and robust error handling for simplicity’s sake. For a more practical example of incorporating transactions in applications, see Transactions in Applications instead.

// Prereq: Create collections. CRUD operations in transactions must be on existing collections.
db.getSiblingDB("mydb1").foo.insert( {abc: 0}, { writeConcern: { w: "majority", wtimeout: 2000 } } );
db.getSiblingDB("mydb2").bar.insert( {xyz: 0}, { writeConcern: { w: "majority", wtimeout: 2000 } } );

// Start a session.
session = db.getMongo().startSession( { readPreference: { mode: "primary" } } );

coll1 = session.getDatabase("mydb1").foo;
coll2 = session.getDatabase("mydb2").bar;

// Start a transaction
session.startTransaction( { readConcern: { level: "local" }, writeConcern: { w: "majority" } } );

// Operations inside the transaction
try {
   coll1.insertOne( { abc: 1 } );
   coll2.insertOne( { xyz: 999 } );
} catch (error) {
   // Abort transaction on error
   session.abortTransaction();
   throw error;
}

// Commit the transaction using write concern set at transaction start
session.commitTransaction();

session.endSession();

Transactions and Sessions

  • Transactions are associated with a session; i.e. you start a transaction for a session.
  • At any given time, you can have at most one open transaction for a session.
  • When using the drivers, each operation in the transaction must be associated with the session. Depending on the driver, the new callback API either requires you to explicitly pass the session to each operation or uses lexical scoping to implicitly pass the session to each operation for you. Refer to your driver specific documentation for details.
  • If a session ends and it has an open transaction, the transaction aborts.

Transactions and MongoDB Drivers

For transactions on MongoDB 4.2 deployments, clients require MongoDB drivers updated for MongoDB 4.2.

Sharded Transactions and MongoDB 4.0 drivers

On sharded clusters with multiple mongos instances, performing transactions with drivers updated for MongoDB 4.0 (instead of MongoDB 4.2) results in errors:

Error Code Error Message
251 cannot continue txnId -1 for session ... with txnId 1
50940 cannot commit with no participants

For transactions on MongoDB 4.0 replica sets, clients require MongoDB drivers updated for MongoDB 4.0 or later.

  • Java 3.8.0
  • Python 3.7.0
  • C 1.11.0
  • C# 2.7
  • Node 3.1.0
  • Ruby 2.6.0
  • Perl 2.0.0
  • PHPC 1.5.0
  • Scala 2.4.0

Transactions and the mongo Shell

The following mongo shell methods are available for transactions:

Transactions and Atomicity

Multi-document transactions are atomic (i.e. provide an “all-or-nothing” proposition)

  • When a transaction commits, all data changes made in the transaction are saved and visible outside the transaction. Until a transaction commits, the data changes made in the transaction are not visible outside the transaction.
  • When a transaction aborts, all data changes made in the transaction are discarded without ever becoming visible. For example, if any operation in the transaction fails, the transaction aborts and all data changes made in the transaction are discarded without ever becoming visible.

Transactions and Operations

Multi-document transactions can be used across multiple operations, collections, databases, and documents.

For transactions:

  • You can specify read/write (CRUD) operations on existing collections. The collections can be in different databases. For a list of CRUD operations, see CRUD Operations.
  • 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 (i.e. explain).
  • For cursors created outside of transactions, you cannot call getMore inside a transaction.
  • For cursors created in a transaction, you cannot call getMore outside the transaction.

Operations that affect the database catalog, such as creating or dropping a collection or an index, are not allowed in multi-document transactions. For example, a multi-document transaction cannot include an insert operation that would result in the creation of a new collection. See Restricted Operations.

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" to ensure that the transaction can acquire the required locks.

Count Operation

To perform a count operation within a transaction, use the $count aggregation stage or the $group (with a $sum expression) aggregation stage.

MongoDB drivers compatible with the 4.0 features provide a collection-level API countDocuments(filter, options) as a helper method that uses the $group with a $sum expression to perform a count. The 4.0 drivers have deprecated the count() API.

Starting in MongoDB 4.0.3, the mongo shell provides the db.collection.countDocuments() helper method that uses the $group with a $sum expression to perform a count.

Informational Operations

Informational commands, such as isMaster, buildInfo, 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 multi-document transactions:

  • Operations that affect the database catalog, such as creating or dropping a collection or an index. For example, a multi-document transaction cannot include an insert operation that would result in the creation of a new collection.

    The listCollections and listIndexes commands and their helper methods are also excluded.

  • Non-CRUD and non-informational operations, such as createUser, getParameter, count, etc. and their helpers.

Read Concern/Write Concern/Read Preference

Transactions and Read Preference

Operations in a transaction use the transaction-level read preference.

Using the drivers, you can set the transaction-level 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.

Multi-document transactions that contain read operations must use read preference 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. That is, any read concern set at the collection and database level is ignored inside the transaction.

You can set the transaction-level 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, client-level read concern is "local" for reads against the primary. See also Transactions and Read Preference.

Multi-document transactions support the following read concern levels:

"local"

  • Read concern "local" returns the most recent data available from the node but can be rolled back.

  • Not Synchronized Across Shards

    For transactions on sharded clusters, read concern "local" reads from views of the data are not synchronized across shards. For a synchronized snapshot view of data, explicitly use "snapshot" read concern.

"majority"

  • Read concern "majority" returns data that has been acknowledged by a majority of the replica set members (i.e. data cannot be rolled back) if the transaction commits with write concern “majority”.

  • If the transaction does not use write concern “majority” for the commit, the "majority" read concern provides no guarantees that read operations read majority-committed data.

  • Not Synchronized Across Shards

    For transactions on sharded clusters, read concern "majority" reads from views of the data are not synchronized across shards. For a synchronized snapshot view of data, explicitly use "snapshot" read concern.

"snapshot"

Synchronized Across Shards

For transactions on sharded clusters, the "snapshot" view of the data is synchronized across shards.

Transactions and Write Concern

Transactions use the transaction-level write concern to commit the write operations. Write operations inside transactions must be issued without explicit write concern specification and use the default write concern. At commit time, the writes are then commited using the transaction-level write concern.

Tip

Do not explicitly set the write concern for the individual write operations inside a transaction. Setting write concerns for the individual write operations inside a transaction results in an error.

You can set the transaction-level write 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, transaction-level write concern defaults to the client-level write concern. By default, client-level read concern is w: 1.

Multi-document transactions support all write concern w values, including:

w: 1

  • Write concern w: 1 returns acknowledgement after the commit has been applied to the primary.

    Important

    When you commit with w: 1, your transaction can be rolled back if there is a failover.

  • When you commit with w: 1 write concern, transaction-level "majority" read concern provides no guarantees that read operations in the transaction read majority-committed data.

  • When you commit with w: 1 write concern, transaction-level "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" returns acknowledgement after the commit has been applied to a majority (M) of voting members; i.e. the commit has been applied to the primary and (M-1) voting secondaries.
  • When you commit with w: "majority" write concern, transaction-level "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" write concern, transaction-level "snapshot" read concern guarantees that operations have from a synchronized snapshot of majority-committed data.

General Information

Production Considerations

For various production considerations with using transactions, see Production Considerations. In addition, or sharded clusters, see also Production Considerations (Sharded Clusters).

Arbiters

Transactions on deployments with arbiters have the following limitation:

  • On a sharded cluster, transactions that span multiple shards will error and abort if any involved shard contains an arbiter. Single shard transactions that involve the shard containing the arbiter are not affected unless read concern majority is disabled.

Disabled Read Concern Majority

Deployments may have disabled read concern majority (--enableMajorityReadConcern false or replication.enableMajorityReadConcern: false); for example, a 3-member PSA (Primary-Secondary-Arbiter) replica set or a sharded cluster with 3-member PSA shards may have disabled read concern majority.

On sharded clusters with a shard that has disabled read concern “majority”:

  • You cannot run transactions with read concern snapshot if the transaction involves that shard. The transaction with read concern snapshot errors and aborts.

    'atClusterTime' is not supported when enableMajorityReadConcern=false
    
  • You cannot run transactions that span multiple shards if the transaction involves that shard. The transaction errors during the commit and aborts.

To check if read concern “majority” is disabled, you can run db.serverStatus() on the mongod instances and check the storageEngine.supportsCommittedReads field. If false, read concern “majority” is disabled.

For more information, see 3-Member Primary-Secondary-Arbiter Architecture and Three Member Primary-Secondary-Arbiter Shards.

Diagnostics

MongoDB provides various transactions metrics:

Feature Compatibility Version (FCV)

Transactions impose a minimum featureCompatibilityVersion for all members of the deployment.

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:

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

For more information, see the setFeatureCompatibilityVersion reference page.

Storage Engines

Multi-document transactions are only available for deployments that use WiredTiger storage engine. They are not available for deployments that use in-memory storage engine.