Transactions事务

On this page本页内容

In MongoDB, an operation on a single document is atomic. 在MongoDB中,对单个文档的操作是原子的。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.由于可以使用嵌入式文档和数组来捕获单个文档结构中的数据之间的关系,而不是跨多个文档和集合进行规范化,因此这种单文档原子性消除了许多实际用例中对多文档事务的需要。

For situations that require atomicity of reads and writes to multiple documents (in a single or multiple collections), MongoDB supports multi-document transactions. 对于需要对多个文档(在单个或多个集合中)进行原子性读写的情况,MongoDB支持多文档事务。With distributed transactions, transactions can be used across multiple operations, collections, databases, documents, and shards.通过分布式事务,可以跨多个操作、集合、数据库、文档和碎片使用事务。

Transactions API事务API

The following example highlights the key components of the transactions API:以下示例重点介绍了transactions API的关键组件:

The example uses the new callback API for working with transactions, which starts a transaction, executes the specified operations, and commits (or aborts on error). 该示例使用新的回调API处理事务,它启动事务,执行指定的操作,并提交(或在出错时中止)。The new callback API also incorporates retry logic for TransientTransactionError or UnknownTransactionCommitResult commit errors.新的回调API还包含TransientTransactionErrorUnknownTransactionCommitResult提交错误的重试逻辑。

Important重要的

  • Recommended. 推荐。Use the MongoDB driver updated for the version of your MongoDB deployment. 使用针对MongoDB部署版本更新的MongoDB驱动程序。For transactions on MongoDB 4.2 deployments (replica sets and sharded clusters), clients must use MongoDB drivers updated for MongoDB 4.2.对于MongoDB 4.2部署(副本集和分片集群)上的事务,客户端必须使用为MongoDB 4.2更新的MongoDB驱动程序。
  • When using the drivers, each operation in the transaction must be associated with the session (i.e. pass in the session to each operation).使用驱动程序时,事务中的每个操作都必须与会话相关联(即将会话传递给每个操作)。
  • Operations in a transaction use transaction-level read concern, transaction-level write concern, and transaction-level read preference.事务中的操作使用事务级读关注点事务级写关注点和事务级读首选项。
  • In MongoDB 4.2 and earlier, you cannot create collections in transactions. 在MongoDB 4.2及更早版本中,不能在事务中创建集合。Write operations that result in document inserts (e.g. insert or update operations with upsert: true) must be on existing collections if run inside transactions.如果在事务内部运行,则导致文档插入的写入操作(例如,使用upsert:true的插入或更新操作)必须在现有集合上。
  • Starting in MongoDB 4.4, you can create collections in transactions implicitly or explicitly. 从MongoDB 4.4开始,您可以隐式或显式地在事务中创建集合。You must use MongoDB drivers updated for 4.4, however. 但是,您必须使用为4.4更新的MongoDB驱动程序。See Create Collections and Indexes In a Transaction for details.有关详细信息,请参阅在事务中创建集合和索引

# 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, read_concern=ReadConcern('local'),
        write_concern=wc_majority,
        read_preference=ReadPreference.PRIMARY)

The example uses the new callback API for working with transactions, which starts a transaction, executes the specified operations, and commits (or aborts on error). The new callback API also incorporates retry logic for TransientTransactionError or UnknownTransactionCommitResult commit errors.

Important

  • Recommended. Use the MongoDB driver updated for the version of your MongoDB deployment. For transactions on MongoDB 4.2 deployments (replica sets and sharded clusters), clients must use MongoDB drivers updated for MongoDB 4.2.
  • When using the drivers, each operation in the transaction must be associated with the session (i.e. pass in the session to each operation).
  • Operations in a transaction use transaction-level read concern, transaction-level write concern, and transaction-level read preference.
  • In MongoDB 4.2 and earlier, you cannot create collections in transactions. Write operations that result in document inserts (e.g. insert or update operations with upsert: true) must be on existing collections if run inside transactions.
  • Starting in MongoDB 4.4, you can create collections in transactions implicitly or explicitly. You must use MongoDB drivers updated for 4.4, however. See Create Collections and Indexes In a Transaction for details.
/*
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);

/*
Create 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));

/* 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()
        .readPreference(ReadPreference.primary())
        .readConcern(ReadConcern.LOCAL)
        .writeConcern(WriteConcern.MAJORITY)
        .build();

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

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

        /*
Important:: You must pass the session to the operations.
*/
        coll1.insertOne(clientSession, new Document("abc", 1));
        coll2.insertOne(clientSession, new Document("xyz", 999));
        return "Inserted into collections in different databases";
    }
};
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();
}

The example uses the new callback API for working with transactions, which starts a transaction, executes the specified operations, and commits (or aborts on error). The new callback API also incorporates retry logic for TransientTransactionError or UnknownTransactionCommitResult commit errors.

Important

  • Recommended. Use the MongoDB driver updated for the version of your MongoDB deployment. For transactions on MongoDB 4.2 deployments (replica sets and sharded clusters), clients must use MongoDB drivers updated for MongoDB 4.2.
  • When using the drivers, each operation in the transaction must be associated with the session (i.e. pass in the session to each operation).
  • Operations in a transaction use transaction-level read concern, transaction-level write concern, and transaction-level read preference.
  • In MongoDB 4.2 and earlier, you cannot create collections in transactions. Write operations that result in document inserts (e.g. insert or update operations with upsert: true) must be on existing collections if run inside transactions.
  • Starting in MongoDB 4.4, you can create collections in transactions implicitly or explicitly. You must use MongoDB drivers updated for 4.4, however. See Create Collections and Indexes In a Transaction for details.
  // 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();
  }

The example uses the new callback API for working with transactions, which starts a transaction, executes the specified operations, and commits (or aborts on error). The new callback API also incorporates retry logic for TransientTransactionError or UnknownTransactionCommitResult commit errors.

Important

  • Recommended. Use the MongoDB driver updated for the version of your MongoDB deployment. For transactions on MongoDB 4.2 deployments (replica sets and sharded clusters), clients must use MongoDB drivers updated for MongoDB 4.2.
  • When using the drivers, each operation in the transaction must be associated with the session (i.e. pass in the session to each operation).
  • Operations in a transaction use transaction-level read concern, transaction-level write concern, and transaction-level read preference.
  • In MongoDB 4.2 and earlier, you cannot create collections in transactions. Write operations that result in document inserts (e.g. insert or update operations with upsert: true) must be on existing collections if run inside transactions.
  • Starting in MongoDB 4.4, you can create collections in transactions implicitly or explicitly. You must use MongoDB drivers updated for 4.4, however. See Create Collections and Indexes In a Transaction for details.
/*
* 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) {
    $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).

$transactionOptions = [
    'readConcern' => new \MongoDB\Driver\ReadConcern(\MongoDB\Driver\ReadConcern::LOCAL),
    'writeConcern' => new \MongoDB\Driver\WriteConcern(\MongoDB\Driver\WriteConcern::MAJORITY, 1000),
    'readPreference' => new \MongoDB\Driver\ReadPreference(\MongoDB\Driver\ReadPreference::RP_PRIMARY),
];

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

The example uses the new callback API for working with transactions, which starts a transaction, executes the specified operations, and commits (or aborts on error). The new callback API incorporates retry logic for "TransientTransactionError" or "UnknownTransactionCommitResult" commit errors.

Important

  • Recommended. Use the MongoDB driver updated for the version of your MongoDB deployment. For transactions on MongoDB 4.2 deployments (replica sets and sharded clusters), clients must use MongoDB drivers updated for MongoDB 4.2.
  • When using the drivers, each operation in the transaction must be associated with the session (i.e. pass in the session to each operation).
  • Operations in a transaction use transaction-level read concern, transaction-level write concern, and transaction-level read preference.
  • In MongoDB 4.2 and earlier, you cannot create collections in transactions. Write operations that result in document inserts (e.g. insert or update operations with upsert: true) must be on existing collections if run inside transactions.
  • Starting in MongoDB 4.4, you can create collections in transactions implicitly or explicitly. You must use MongoDB drivers updated for 4.4, however. See Create Collections and Indexes In a Transaction for details.

# 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)

The example uses the new callback API for working with transactions, which starts a transaction, executes the specified operations, and commits (or aborts on error). The new callback API also incorporates retry logic for TransientTransactionError or UnknownTransactionCommitResult commit errors.

Important

  • Recommended. Use the MongoDB driver updated for the version of your MongoDB deployment. For transactions on MongoDB 4.2 deployments (replica sets and sharded clusters), clients must use MongoDB drivers updated for MongoDB 4.2.
  • When using the drivers, each operation in the transaction must be associated with the session (i.e. pass in the session to each operation).
  • Operations in a transaction use transaction-level read concern, transaction-level write concern, and transaction-level read preference.
  • In MongoDB 4.2 and earlier, you cannot create collections in transactions. Write operations that result in document inserts (e.g. insert or update operations with upsert: true) must be on existing collections if run inside transactions.
  • Starting in MongoDB 4.4, you can create collections in transactions implicitly or explicitly. You must use MongoDB drivers updated for 4.4, however. See Create Collections and Indexes In a Transaction for details.
static bool
with_transaction_example (bson_error_t *error)
{
   mongoc_client_t *client = NULL;
   mongoc_write_concern_t *wc = NULL;
   mongoc_read_concern_t *rc = NULL;
   mongoc_read_prefs_t *rp = 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. */
   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 ();
   rp = mongoc_read_prefs_new (MONGOC_READ_PRIMARY);
   rc = mongoc_read_concern_new ();
   mongoc_read_concern_set_level (rc, MONGOC_READ_CONCERN_LEVEL_LOCAL);
   mongoc_transaction_opts_set_read_prefs (txn_opts, rp);
   mongoc_transaction_opts_set_read_concern (txn_opts, rc);
   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_read_concern_destroy (rc);
   mongoc_read_prefs_destroy (rp);
   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;
   bool success = false;
   bool ret = false;

   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, NULL /* opts */, *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 (999));
   ret =
      mongoc_collection_insert_one (coll, doc, NULL /* opts */, *reply, error);
   if (!ret) {
      goto fail;
   }

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

The example uses the new callback API for working with transactions, which starts a transaction, executes the specified operations, and commits (or aborts on error). The new callback API also incorporates retry logic for TransientTransactionError or UnknownTransactionCommitResult commit errors.

Important

  • Recommended. Use the MongoDB driver updated for the version of your MongoDB deployment. For transactions on MongoDB 4.2 deployments (replica sets and sharded clusters), clients must use MongoDB drivers updated for MongoDB 4.2.
  • When using the drivers, each operation in the transaction must be associated with the session (i.e. pass in the session to each operation).
  • Operations in a transaction use transaction-level read concern, transaction-level write concern, and transaction-level read preference.
  • In MongoDB 4.2 and earlier, you cannot create collections in transactions. Write operations that result in document inserts (e.g. insert or update operations with upsert: true) must be on existing collections if run inside transactions.
  • Starting in MongoDB 4.4, you can create collections in transactions implicitly or explicitly. You must use MongoDB drivers updated for 4.4, however. See Create Collections and Indexes In a Transaction for details.
// 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{"mongodb://localhost/?replicaSet=replset"}};

write_concern wc_majority{};
wc_majority.acknowledge_level(write_concern::level::k_majority);

read_concern rc_local{};
rc_local.acknowledge_level(read_concern::level::k_local);

read_preference rp_primary{};
rp_primary.mode(read_preference::read_mode::k_primary);

// 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 (const mongocxx::exception& 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);
    opts.read_concern(rc_local);
    opts.read_preference(rp_primary);

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

return EXIT_SUCCESS;

The example uses the new callback API for working with transactions, which starts a transaction, executes the specified operations, and commits (or aborts on error). The new callback API also incorporates retry logic for TransientTransactionError or UnknownTransactionCommitResult commit errors.

Important

  • Recommended. Use the MongoDB driver updated for the version of your MongoDB deployment. For transactions on MongoDB 4.2 deployments (replica sets and sharded clusters), clients must use MongoDB drivers updated for MongoDB 4.2.
  • When using the drivers, each operation in the transaction must be associated with the session (i.e. pass in the session to each operation).
  • Operations in a transaction use transaction-level read concern, transaction-level write concern, and transaction-level read preference.
  • In MongoDB 4.2 and earlier, you cannot create collections in transactions. Write operations that result in document inserts (e.g. insert or update operations with upsert: true) must be on existing collections if run inside transactions.
  • Starting in MongoDB 4.4, you can create collections in transactions implicitly or explicitly. You must use MongoDB drivers updated for 4.4, however. See Create Collections and Indexes In a Transaction for details.
// 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(
        readPreference: ReadPreference.Primary,
        readConcern: ReadConcern.Local,
        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) =>
        {
            collection1.InsertOne(s, new BsonDocument("abc", 1), cancellationToken: ct);
            collection2.InsertOne(s, new BsonDocument("xyz", 999), cancellationToken: ct);
            return "Inserted into collections in different databases";
        },
        transactionOptions,
        cancellationToken);
}

This example uses the core API. Because the core API does not incorporate retry logic for "TransientTransactionError" or "UnknownTransactionCommitResult" commit errors, the example includes explicit logic to retry the transaction for these errors:

Important

  • Recommended. Use the MongoDB driver updated for the version of your MongoDB deployment. For transactions on MongoDB 4.2 deployments (replica sets and sharded clusters), clients must use MongoDB drivers updated for MongoDB 4.2.
  • When using the drivers, each operation in the transaction must be associated with the session (i.e. pass in the session to each operation).
  • Operations in a transaction use transaction-level read concern, transaction-level write concern, and transaction-level read preference.
  • In MongoDB 4.2 and earlier, you cannot create collections in transactions. Write operations that result in document inserts (e.g. insert or update operations with upsert: true) must be on existing collections if run inside transactions.
  • Starting in MongoDB 4.4, you can create collections in transactions implicitly or explicitly. You must use MongoDB drivers updated for 4.4, however. See Create Collections and Indexes In a Transaction for details.
sub runTransactionWithRetry {
    my ( $txnFunc, $session ) = @_;

    LOOP: {
        eval {
            $txnFunc->($session); # performs transaction
        };
        if ( my $error = $@ ) {
            print("Transaction aborted-> Caught exception during transaction.\n");
            # If transient error, retry the whole transaction
            if ( $error->has_error_label("TransientTransactionError") ) {
                print("TransientTransactionError, retrying transaction ->..\n");
                redo LOOP;
            }
            else {
                die $error;
            }
        }
    }

    return;
}

sub commitWithRetry {
    my ($session) = @_;

    LOOP: {
        eval {
            $session->commit_transaction(); # Uses write concern set at transaction start.
            print("Transaction committed->\n");
        };
        if ( my $error = $@ ) {
            # Can retry commit
            if ( $error->has_error_label("UnknownTransactionCommitResult") ) {
                print("UnknownTransactionCommitResult, retrying commit operation ->..\n");
                redo LOOP;
            }
            else {
                print("Error during commit ->..\n");
                die $error;
            }
        }
    }

    return;
}

# Updates two collections in a transactions

sub updateEmployeeInfo {
    my ($session) = @_;
    my $employeesCollection = $session->client->ns("hr.employees");
    my $eventsCollection    = $session->client->ns("reporting.events");

    $session->start_transaction(
        {
            readConcern  => { level => "snapshot" },
            writeConcern => { w     => "majority" },
            readPreference => 'primary',
        }
    );

    eval {
        $employeesCollection->update_one(
            { employee => 3 }, { '$set' => { status => "Inactive" } },
            { session => $session},
        );
        $eventsCollection->insert_one(
            { employee => 3, status => { new => "Inactive", old => "Active" } },
            { session => $session},
        );
    };
    if ( my $error = $@ ) {
        print("Caught exception during transaction, aborting->\n");
        $session->abort_transaction();
        die $error;
    }

    commitWithRetry($session);
}

# Start a session
my $session = $client->start_session();

eval {
    runTransactionWithRetry(\&updateEmployeeInfo, $session);
};
if ( my $error = $@ ) {
    # Do something with error
}

$session->end_session();

The example uses the new callback API for working with transactions, which starts a transaction, executes the specified operations, and commits (or aborts on error). The new callback API incorporates retry logic for "TransientTransactionError" or "UnknownTransactionCommitResult" commit errors.

Important

  • Recommended. Use the MongoDB driver updated for the version of your MongoDB deployment. For transactions on MongoDB 4.2 deployments (replica sets and sharded clusters), clients must use MongoDB drivers updated for MongoDB 4.2.
  • When using the drivers, each operation in the transaction must be associated with the session (i.e. pass in the session to each operation).
  • Operations in a transaction use transaction-level read concern, transaction-level write concern, and transaction-level read preference.
  • In MongoDB 4.2 and earlier, you cannot create collections in transactions. Write operations that result in document inserts (e.g. insert or update operations with upsert: true) must be on existing collections if run inside transactions.
  • Starting in MongoDB 4.4, you can create collections in transactions implicitly or explicitly. You must use MongoDB drivers updated for 4.4, however. See Create Collections and Indexes In a Transaction for details.
# 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.new 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 uses the core API. Because the core API does not incorporate retry logic for "TransientTransactionError" or "UnknownTransactionCommitResult" commit errors, the example includes explicit logic to retry the transaction for these errors:

Important

  • Recommended. Use the MongoDB driver updated for the version of your MongoDB deployment. For transactions on MongoDB 4.2 deployments (replica sets and sharded clusters), clients must use MongoDB drivers updated for MongoDB 4.2.
  • When using the drivers, each operation in the transaction must be associated with the session (i.e. pass in the session to each operation).
  • Operations in a transaction use transaction-level read concern, transaction-level write concern, and transaction-level read preference.
  • In MongoDB 4.2 and earlier, you cannot create collections in transactions. Write operations that result in document inserts (e.g. insert or update operations with upsert: true) must be on existing collections if run inside transactions.
  • Starting in MongoDB 4.4, you can create collections in transactions implicitly or explicitly. You must use MongoDB drivers updated for 4.4, however. See Create Collections and Indexes In a Transaction for details.
  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)
  }
}

The example uses the new callback API for working with transactions, which starts a transaction, executes the specified operations, and commits (or aborts on error). The new callback API incorporates retry logic for "TransientTransactionError" or "UnknownTransactionCommitResult" commit errors.

Important

  • Recommended. Use the MongoDB driver updated for the version of your MongoDB deployment. For transactions on MongoDB 4.2 deployments (replica sets and sharded clusters), clients must use MongoDB drivers updated for MongoDB 4.2.
  • When using the drivers, each operation in the transaction must be associated with the session (i.e. pass in the session to each operation).
  • Operations in a transaction use transaction-level read concern, transaction-level write concern, and transaction-level read preference.
  • In MongoDB 4.2 and earlier, you cannot create collections in transactions. Write operations that result in document inserts (e.g. insert or update operations with upsert: true) must be on existing collections if run inside transactions.
  • Starting in MongoDB 4.4, you can create collections in transactions implicitly or explicitly. You must use MongoDB drivers updated for 4.4, however. See Create Collections and Indexes In a Transaction for details.
// WithTransactionExample is an example of using the Session.WithTransaction function.
func WithTransactionExample() {
	ctx := context.Background()
	// 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/"
	var uri string

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

	// Prereq: Create collections.
	wcMajority := writeconcern.New(writeconcern.WMajority(), writeconcern.WTimeout(1*time.Second))
	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(sessCtx mongo.SessionContext) (interface{}, error) {
		// Important: You must pass sessCtx as the Context parameter to the operations for them to be executed in the
		// transaction.
		if _, err := fooColl.InsertOne(sessCtx, bson.D{{"abc", 1}}); err != nil {
			return nil, err
		}
		if _, err := barColl.InsertOne(sessCtx, 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 {
		panic(err)
	}
	defer session.EndSession(ctx)

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

See also参阅

For an example in mongo shell, see mongo Shell Example.有关mongo shell中的示例,请参阅mongo shell示例

Transactions and Atomicity事务和原子性

Distributed Transactions and Multi-Document Transactions分布式事务和多文档事务

Starting in MongoDB 4.2, the two terms are synonymous. 从MongoDB 4.2开始,这两个术语是同义词。Distributed transactions refer to multi-document transactions on sharded clusters and replica sets. 分布式事务是指分片集群和副本集上的多文档事务。Multi-document transactions (whether on sharded clusters or replica sets) are also known as distributed transactions starting in MongoDB 4.2.从MongoDB 4.2开始,多文档事务(无论是在分片集群还是副本集上)也称为分布式事务。

For situations that require atomicity of reads and writes to multiple documents (in a single or multiple collections), MongoDB supports multi-document transactions:对于需要对多个文档(在单个或多个集合中)进行原子性读写的情况,MongoDB支持多文档事务:

Multi-document transactions are atomic (i.e. provide an “all-or-nothing” proposition):多文档事务是原子的(即提供“全部或无”命题):

Important

In most cases, multi-document transaction incurs a greater performance cost over single document writes, and the availability of multi-document transactions 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.也就是说,对于许多场景,适当地建模数据将最大限度地减少对多文档事务的需求。

For additional transactions usage considerations (such as runtime limit and oplog size limit), see also Production Considerations.有关其他事务使用注意事项(如运行时限制和oplog大小限制),请参阅生产注意事项

Transactions and Operations事务和操作

Distributed transactions can be used across multiple operations, collections, databases, documents, and, starting in MongoDB 4.2, shards.分布式事务可以跨多个操作、集合、数据库、文档以及从MongoDB 4.2开始的碎片使用。

For transactions:对于事务:

For a list of operations not supported in transactions, 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.在启动事务之前立即创建或删除集合时,如果在事务中访问了集合,请使用写关注点"majority"发出创建或删除操作,以确保事务可以获得所需的锁。

Create Collections and Indexes In a Transaction在事务中创建集合和索引

Starting in MongoDB 4.4 with feature compatibility version (fcv) "4.4", you can create collections and indexes inside a multi-document transaction unless the transaction is a cross-shard write transaction. 功能兼容版本(fcv)"4.4"的MongoDB 4.4开始,您可以在多文档事务中创建集合和索引,除非该事务是跨切分写入事务。With "4.2" or less, operations that affect the database catalog, such as creating or dropping a collection or an index, are disallowed in transactions.对于"4.2"或更低版本,事务中不允许执行影响数据库目录的操作,例如创建或删除集合或索引。

When creating a collection inside a transaction:在事务内创建集合时:

When creating an index inside a transaction [1], the index to create must be on either:在事务内创建索引[1]时,要创建的索引必须位于以下任一位置:

  • a non-existing collection. 不存在的集合。The collection is created as part of the operation.集合是作为操作的一部分创建的。
  • a new empty collection created earlier in the same transaction.先前在同一事务中创建的新空集合。
[1]You can also run db.collection.createIndex() and db.collection.createIndexes() on existing indexes to check for existence. 还可以对现有索引运行db.collection.createIndex()db.collection.createIndexes(),以检查是否存在。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.例如,如果在一个碎片中写入现有集合,并在另一个碎片中隐式创建集合,MongoDB无法在同一事务中执行这两个操作。
  • For explicit creation of a collection or an index inside a transaction, the transaction read concern level must be "local". 对于在事务内显式创建集合或索引,事务读取关注级别必须为"local"Explicit creation is through:显式创建是通过:

    Command命令Method方法
    create db.createCollection()
    createIndexes
  • The parameter shouldMultiDocTxnCreateCollectionAndIndexes must be true (the default). 参数shouldMultiDocTxnCreateCollectionAndIndexes必须为true(默认值)。When setting the parameter for a sharded cluster, set the parameter on all shards.为分片簇设置参数时,请在所有分片上设置该参数。

Count Operation计数操作

To perform a count operation within a transaction, use the $count aggregation stage or the $group (with a $sum expression) aggregation stage.要在事务中执行计数操作,请使用$count聚合阶段或$group(带有$sum表达式)聚合阶段。

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. 与4.0功能兼容的MongoDB驱动程序提供了一个集合级API countDocuments(filter, options),作为一个助手方法,使用$group$sum表达式来执行计数。The 4.0 drivers have deprecated the count() API.4.0驱动程序不推荐使用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.从MongoDB 4.0.3开始,mongo shell提供了db.collection.countDocuments()辅助方法,该方法使用带有$sum表达式的$group来执行计数。

Distinct Operation独特的操作

To perform a distinct operation within a transaction:要在事务中执行不同的操作:

  • For unsharded collections, you can use the db.collection.distinct() method/the distinct command as well as the aggregation pipeline with the $group stage.对于未分块的集合,可以使用db.collection.distinct()方法/distinct命令以及$group阶段的聚合管道。
  • For sharded collections, you cannot use the db.collection.distinct() method or the distinct command.对于分片集合,不能使用db.collection.distinct()方法或distinct命令。

    To find the distinct values for a sharded collection, use the aggregation pipeline with the $group stage instead. 要查找分片集合的不同值,请将聚合管道与$group阶段一起使用。For example:例如:

    • Instead of db.coll.distinct("x"), use不是使用db.coll.distinct("x"),而是使用

      db.coll.aggregate([
         { $group: { _id: null, distinctValues: { $addToSet: "$x" } } },
         { $project: { _id: 0 } }
      ])
    • Instead of db.coll.distinct("x", { status: "A" }), use:不是使用db.coll.distinct("x", { status: "A" }),而是使用:

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

    The pipeline returns a cursor to a document:管道将游标返回到文档:

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

    Iterate the cursor to access the results document.迭代游标以访问结果文档。

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.在事务中允许使用信息性命令,如isMasterbuildInfoconnectionStatus(及其助手方法);但是,它们不能是事务中的第一个操作。

Restricted Operations受限操作

Changed in version 4.4.在版本4.4中更改。

The following operations are not allowed in transactions:事务中不允许进行以下操作:

Transactions and Sessions事务和会话

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.默认情况下,客户端级别的读取首选项是primary

Multi-document transactions that contain read operations must use read preference primary. 包含读取操作的多文档事务必须使用读取首选项primaryAll 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. 默认情况下,对于针对主服务器的读取,客户端级别的读取关注点是"local"的。See also:另见:

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.读取关注点"local"返回节点上可用的最新数据,但可以回滚。
  • For transactions on sharded cluster, "local" read concern cannot guarantee that the data is from the same snapshot view across the shards. 对于分片集群上的事务,"local"读关注点不能保证数据来自分片上的同一快照视图。If snapshot isolation is required, use "snapshot" read concern.如果需要快照隔离,请使用"snapshot"读取问题。
  • Starting in MongoDB 4.4, with feature compatibility version (fcv) "4.4" or greater, you can create collections and indexes inside a transaction. 从MongoDB 4.4开始,使用功能兼容性版本(fcv)"4.4"或更高版本,您可以在事务中创建集合和索引If explicitly creating a collection or an index, the transaction must use read concern "local". 如果显式创建集合或索引,则事务必须使用"local"读关注点。Implicit creation of a collection can use any of the read concerns available for transactions.隐式创建集合可以使用事务可用的任何读取关注点。

"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”.如果事务以写入关注点"majority"提交,则读关注"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.如果事务没有将写关注点"majority"用于提交,"majority"读关注点不保证读操作读取多数提交的数据。
  • For transactions on sharded cluster, "majority" read concern cannot guarantee that the data is from the same snapshot view across the shards. 对于分片集群上的事务,"majority"读关注点不能保证数据来自分片上的相同快照视图。If snapshot isolation is required, use "snapshot" read concern.如果需要快照隔离,请使用"snapshot"读关注点。

"snapshot"

  • Read concern "snapshot" returns data from a snapshot of majority committed data if the transaction commits with write concern “majority”.如果事务以写关注点“多数”提交,则读关注点"snapshot"从多数提交数据的快照返回数据。
  • If the transaction does not use write concern “majority” for the commit, the "snapshot" read concern provides no guarantee that read operations used a snapshot of majority-committed data.如果事务没有将写关注点"majority"用于提交,“快照”读关注点不能保证读操作使用了多数提交数据的快照。
  • For transactions on sharded clusters, the "snapshot" view of the data is synchronized across shards.对于分片集群上的事务,数据的"snapshot"视图是跨分片同步的。

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 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, transaction-level write concern defaults to the client-level write concern. 如果事务级写入关注点和会话级写入关注点未设置,则事务级写入关注点默认为客户端级写入关注点。By default, client-level write concern is w: 1. 默认情况下,客户端级别的写关注点是w: 1See also Default MongoDB Read Concerns/Write Concerns.另请参阅默认MongoDB读关注点/写关注点

Transactions support all write concern w values, including:事务支持所有写关注点w值,包括:

w: 1

  • Write concern w: 1 returns acknowledgement after the commit has been applied to the primary.写关注点w:1在提交应用于主服务器后返回确认。

    Important重要的

    When you commit with w: 1, your transaction can be rolled back if there is a failover.使用w: 1提交时,如果存在故障转移,则可以回滚事务

  • 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.书面关注w: "majority"在承诺适用于多数(M)投票成员后返回确认;也就是说,提交已应用于主要和(M-1)投票辅助。
  • 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.当您使用w: "majority"写入关注点进行提交时,事务级别的"snapshot"读取关注点保证操作已从多数提交数据的同步快照中恢复。

Note

Regardless of the write concern specified for the transaction, the commit operation for a sharded cluster transaction includes some parts that use {w: "majority", j: true} write concern.不管为事务指定的写关注点是什么,分片集群事务的提交操作都包括一些使用{w: "majority", j: true}写关注点的部分。

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 whose write operations span multiple shards will error and abort if any transaction operation reads from or writes to a shard that contains an arbiter.如果任何事务操作读取或写入包含仲裁器的分片,则其写入操作跨越多个分片的事务将出错并中止。

See also Disabled Read Concern Majority for transaction restrictions on shards that have disabled read concern majority.另请参阅禁用的读取关注多数,了解已禁用读取关注多数的碎片上的事务限制。

Disabled Read Concern Majority禁用阅读关注点多数

A 3-member PSA (Primary-Secondary-Arbiter) replica set or a sharded cluster with 3-member PSA shards may have disabled read concern majority (--enableMajorityReadConcern false or replication.enableMajorityReadConcern: false)三成员PSA(主从仲裁器)副本集或具有三成员PSA碎片的分片群集可能已禁用读关注多数(--enableMajorityReadConcern falsereplication.enableMajorityReadConcern: false

On sharded clusters,在分片群集上,
  • If a transaction involves a shard that has disabled read concern “majority”, you cannot use read concern "snapshot" for the transaction. 如果事务涉及已禁用读关注点"majority"的碎片,则不能对该事务使用读关注点"snapshot"You can only use read concern "local" or "majority" for the transaction. 您只能在事务中使用"local""majority"If you use read concern "snapshot", the transaction errors and aborts.如果使用"snapshot",事务将出错并中止。

    readConcern level 'snapshot' is not supported in sharded clusters when enableMajorityReadConcern=false.
  • Transactions whose write operations span multiple shards will error and abort if any of the transaction’s read or write operations involves a shard that has disabled read concern "majority".如果事务的任何读或写操作涉及已禁用读关注"majority"的碎片,则其写操作跨越多个碎片的事务将出错并中止。
On replica set,在复制集上,

You can specify read concern "local" or "majority" or "snapshot" even in the replica set has disabled read concern “majority”.即使在副本集中禁用了读取关注点"majority",也可以指定读取关注点"local""majority""snapshot"

However, if you are planning to transition to a sharded cluster with disabled read concern majority shards, you may wish to avoid using read concern "snapshot".但是,如果您计划过渡到具有禁用的读关注多数碎片的分片集群,您可能希望避免使用读关注"snapshot"(快照)。

Tip

To check if read concern “majority” is disabled, You can run db.serverStatus() on the mongod instances and check the storageEngine.supportsCommittedReads field. 要检查读取关注点“多数”是否已禁用,可以在mongod实例上运行db.serverStatus(),并检查storageEngine.supportsCommittedReads字段。If false, read concern “majority” is disabled.如果为false,则禁用阅读关注"majority"

For more information, see 3-Member Primary-Secondary-Arbiter Architecture and Three Member Primary-Secondary-Arbiter Shards.有关更多信息,请参阅三成员主从仲裁器体系结构三成员主从仲裁器碎片

Shard Configuration Restriction碎片配置限制

You cannot run transactions on a sharded cluster that has a shard with writeConcernMajorityJournalDefault set to false (such as a shard with a voting member that uses the in-memory storage engine).不能在writeConcernMajorityJournalDefault设置为false的分片群集上运行事务(例如,使用内存存储引擎的投票成员的分片)。

Note

Regardless of the write concern specified for the transaction, the commit operation for a sharded cluster transaction includes some parts that use {w: "majority", j: true} write concern.不管为事务指定的写关注点是什么,分片集群事务的提交操作都包括一些使用{w: "majority", j: true}写关注点的部分。

Diagnostics诊断学

MongoDB provides various transactions metrics:MongoDB提供了各种事务度量:

Via 
Returns transactions metrics.
$currentOp aggregation pipeline

Returns:

currentOp command

Returns:

mongod and mongos log messages Includes information on slow transactions (i.e. transactions that exceed the operationProfiling.slowOpThresholdMs threshhold) under the TXN log component.包括TXN日志组件下有关慢速事务(即超过operationProfiling.slowOpThresholdMs阈值的事务)的信息。

Feature Compatibility Version (FCV)功能兼容性版本(FCV)

To use transactions, the featureCompatibilityVersion for all members of the deployment must be at least:要使用事务,部署的所有成员的featureCompatibilityVersion必须至少为:

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:要检查fCV中是否有成员,请连接到该成员并运行以下命令:

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

For more information, see the setFeatureCompatibilityVersion reference page.有关更多信息,请参阅setFeatureCompatibilityVersion参考页。

Storage Engines存储引擎

Starting in MongoDB 4.2, multi-document transactions are supported on replica sets and sharded clusters where:从MongoDB 4.2开始,在副本集和分片集群上支持多文档事务,其中:

  • the primary uses the WiredTiger storage engine, and主服务器使用WiredTiger存储引擎
  • the secondary members use either the WiredTiger storage engine or the in-memory storage engines.辅助成员使用WiredTiger存储引擎或内存存储引擎。

In MongoDB 4.0, only replica sets using the WiredTiger storage engine supported transactions.在MongoDB 4.0中,只有使用WiredTiger存储引擎的副本集支持事务。

Note

You cannot run transactions on a sharded cluster that has a shard with writeConcernMajorityJournalDefault set to false, such as a shard with a voting member that uses the in-memory storage engine.不能在writeConcernMajorityJournalDefault设置为false的分片群集上运行事务,例如使用内存存储引擎的投票成员的分片。

Additional Transactions Topics其他事务主题