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


Use the Select your language drop-down menu in the upper-right to set the language of the following example.使用右上角的“选择语言”下拉菜单设置以下示例的语言。


This example highlights the key components of the transactions API.本例重点介绍了事务 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). 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. See Create Collections and Indexes In a Transaction.

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;
BSON_UNUSED (ctx);
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. See Create Collections and Indexes In a Transaction.

// 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. See Create Collections and Indexes In a Transaction.

// 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); }

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. See Create Collections and Indexes In a Transaction.

// 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(ctx, clientOpts) if err != nil { return 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 { 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 }

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. See Create Collections and Indexes In a Transaction.

/*
  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 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. See Create Collections and Indexes In a Transaction.

# 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). 该示例使用新的回调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.如果在事务内部运行,则导致文档插入的写入操作(例如,insertupsert:true的更新操作)必须位于现有集合上。

  • Starting in MongoDB 4.4, you can create collections in transactions implicitly or explicitly. 从MongoDB 4.4开始,您可以在事务中隐式或显式创建集合。See Create Collections and Indexes In a Transaction.请参见在事务中创建集合和索引

  // 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 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. See Create Collections and Indexes In a Transaction.

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 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. See Create Collections and Indexes In a Transaction.

/*
 * 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).
$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 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. See Create Collections and Indexes In a Transaction.

# 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 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. See Create Collections and Indexes In a Transaction.

# 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. See Create Collections and Indexes In a Transaction.

/*
 * 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) } }
Tip提示
See also: 参阅:

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

Transactions and Atomicity事务和原子性

Note注意
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支持多文档事务:

  • In version 4.0, MongoDB supports multi-document transactions on replica sets.版本4.0中,MongoDB支持副本集上的多文档事务。
  • In version 4.2, MongoDB introduces distributed transactions, which adds support for multi-document transactions on sharded clusters and incorporates the existing support for multi-document transactions on replica sets.版本4.2中,MongoDB引入了分布式事务,它增加了对分片集群上多文档事务的支持,并合并了对副本集上多文档事务的现有支持。

    To use 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驱动程序。

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. 当事务提交时,事务中所做的所有数据更改都将被保存,并在事务外部可见。That is, a transaction will not commit some of its changes while rolling back others.也就是说,事务在回滚其他更改时不会提交其部分更改。

    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" can read the results of write 1 without seeing write 2.例如,如果事务已提交,且写入1在分片a上可见,但写入2在分片B上尚不可见,则外部读取-读取关注点"local"可以读取写入1的结果,而不查看写入2。

  • 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.例如,如果事务中的任何操作失败,事务将中止,事务中所做的所有数据更改将被丢弃,而不会变得可见。
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:对于事务:

  • You can specify read/write (CRUD) operations on existing collections. 可以对现有集合指定读/写(CRUD)操作。For a list of CRUD operations, see CRUD Operations.有关CRUD操作的列表,请参阅CRUD操作
  • Starting in MongoDB 4.4, you can create collections and indexes in transactions. 从MongoDB 4.4开始,您可以在事务中创建集合和索引。For details, see Create Collections and Indexes In a Transaction有关详细信息,请参阅在事务中创建集合和索引
  • 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.例如,如果在一个分片中写入现有集合,并在另一个分片中隐式创建集合,MongoDB无法在同一事务中执行这两个操作。

  • You cannot write to capped collections. (Starting in MongoDB 4.2)您不能向封顶集合写入。(从MongoDB 4.2开始
  • You cannot use read concern "snapshot" when reading from a capped collection. (Starting in MongoDB 5.0)封顶集合读取时,不能使用读取关注点"snapshot"。(从MongoDB 5.0开始
  • You cannot read/write to collections in the config, admin, or local databases.无法读取/写入configadminlocal数据库中的集合。
  • You cannot write to system.* collections.无法写入system.*集合。
  • You cannot return the supported operation's query plan (i.e. explain).您不能返回受支持操作的查询计划(即explain)。
  • For cursors created outside of a transaction, you cannot call getMore inside the transaction.对于在事务外部创建的游标,不能在事务内部调用getMore
  • For cursors created in a transaction, you cannot call getMore outside the transaction.对于在事务中创建的游标,不能在事务外部调用getMore

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, you can perform the following operations inside of a multi-document transaction as long as the transaction is not a cross-shard write transaction:从MongoDB 4.4开始,只要事务不是跨分片写入事务,就可以在多文档事务中执行以下操作:

  • Create collections.创建集合。
  • Create indexes on new empty collections created earlier in the same transaction.在同一事务中先前创建的新空集合上创建索引。

In MongoDB 4.2 and earlier, operations that affect the database catalog, such as creating or dropping a collection or an index, are disallowed in transactions.在MongoDB 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方法
    createdb.createCollection()
    createIndexes
Tip提示

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驱动程序提供了一个集合级APIcountDocuments(filter, options),作为一个助手方法,使用$group$sum表达式来执行计数。The 4.0 drivers have deprecated the count() API.4.0驱动程序不推荐使用count() API。

Starting in MongoDB 4.0.3, mongosh provides the db.collection.countDocuments() helper method that uses the $group with a $sum expression to perform a count.从MongoDB 4.0.3开始,mongosh提供了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 hello, buildInfo, connectionStatus (and their helper methods) are allowed in transactions; however, they cannot be the first operation in the transaction.事务中允许使用信息性命令,如hellobuildInfoconnectionStatus(及其助手方法);但是,它们不能是事务中的第一个操作。

Restricted Operations受限操作

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

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

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. 使用驱动程序时,事务中的每个操作都必须与会话相关联。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/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, you can create collections and indexes inside a transaction. 从MongoDB 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"提交,则读关注点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.如果事务没有使用写入关注点"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".如果事务以写关注点"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, the transaction-level write concern defaults to the client-level write concern of:如果事务级写入关注点和会话级写入关注点未设置,则事务级写入关注点默认为客户端级写入关注点:

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.
  • 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.
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}写关注点的部分。

Starting in MongoDB 5.0, the new server parameter coordinateCommitReturnImmediatelyAfterPersistingDecision controls when transaction commit decisions are returned to the client. 从MongoDB 5.0开始,新的服务器参数coordinateCommitReturnImmediatelyAfterPersistingDecision控制事务提交决策返回到客户端后立即返回。In previous versions of MongoDB, the shard transaction coordinator waited for all members to acknowledge a multi-document transaction commit before returning the commit decision to the client.在以前版本的MongoDB中, 分片事务协调器等待所有成员确认多文档事务提交,然后将提交决定返回给客户端。

If you specify a "majority" write concern for a multi-document transaction and the transaction fails to replicate to the calculated majority of replica set members, then the transaction may not immediately roll back on replica set members. 如果您为多文档事务指定了"majority"写入关注点,并且该事务未能复制到计算出的多数副本集成员,则该事务可能不会立即在副本集成员上回滚。The replica set will be eventually consistent. 副本集最终将保持一致A transaction is always applied or rolled back on all replica set members.事务始终应用于或回滚所有副本集成员。

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.如果任何事务操作读取或写入包含仲裁器的分片,则其写入操作跨越多个分片的事务将出错并中止。

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提供了各种事务度量:

SourceReturns返回:
db.serverStatus() method方法
serverStatus command命令
Returns transactions metrics.返回事务度量。
$currentOp aggregation pipeline聚合管道

Returns:返回:

db.currentOp() method方法
currentOp command命令

Returns:返回:

mongod and mongos log messages记录消息Includes information on slow transactions (i.e. transactions that exceed the operationProfiling.slowOpThresholdMs threshold) 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 Set4.0
Sharded Cluster4.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.有关更多信息,请参阅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其他事务主题

←  Database ReferencesDrivers API →