Session.commitTransaction()
Definition
New in version 4.0.
Saves the changes made by the operations in the multi-documenttransaction and ends the transaction.
Availability
- In version 4.0, MongoDB supports multi-documenttransactions on replica sets.
- In version 4.2, MongoDB introduces distributedtransactions, which adds support for multi-documenttransactions on sharded clusters and incorporates the existingsupport for multi-document transactions on replica sets.
Behavior
Write Concern
When commiting the transaction, the session uses the write concernspecified at the transaction start. SeeSession.startTransaction()
.
If you commit using "w: 1"
write concern,your transaction can be rolled back during the failover process.
Atomicity
When a transaction commits, all data changes made in the transactionare saved and visible outside the transaction. That is, a transactionwill not commit some of its changes while rolling back others.
Until a transaction commits, the data changes made in thetransaction are not visible outside the transaction.
However, when a transaction writes to multiple shards, not alloutside read operations need to wait for the result of the committedtransaction to be visible across the shards. For example, if atransaction is committed and write 1 is visible on shard A but write2 is not yet visible on shard B, an outside read at read concern"local"
can read the results of write 1 withoutseeing write 2.
Retryable
If the commit operation encounters an error, MongoDB drivers retry thecommit operation a single time regardless of whetherretryWrites
is set to false
. For more information, seeTransaction Error Handling.
Example
Consider a scenario where as changes are made to an employee’s recordin the hr
database, you want to ensure that the events
collection in the reporting
database are in sync with the hr
changes. That is, you want to ensure that these writes are done as asingle transaction, such that either both operations succeed or fail.
The employees
collection in the hr
database has the followingdocuments:
- { "_id" : ObjectId("5af0776263426f87dd69319a"), "employee" : 3, "name" : { "title" : "Mr.", "name" : "Iba Ochs" }, "status" : "Active", "department" : "ABC" }
- { "_id" : ObjectId("5af0776263426f87dd693198"), "employee" : 1, "name" : { "title" : "Miss", "name" : "Ann Thrope" }, "status" : "Active", "department" : "ABC" }
- { "_id" : ObjectId("5af0776263426f87dd693199"), "employee" : 2, "name" : { "title" : "Mrs.", "name" : "Eppie Delta" }, "status" : "Active", "department" : "XYZ" }
The events
collection in the reporting
database has thefollowing documents:
- { "_id" : ObjectId("5af07daa051d92f02462644a"), "employee" : 1, "status" : { "new" : "Active", "old" : null }, "department" : { "new" : "ABC", "old" : null } }
- { "_id" : ObjectId("5af07daa051d92f02462644b"), "employee" : 2, "status" : { "new" : "Active", "old" : null }, "department" : { "new" : "XYZ", "old" : null } }
- { "_id" : ObjectId("5af07daa051d92f02462644c"), "employee" : 3, "status" : { "new" : "Active", "old" : null }, "department" : { "new" : "ABC", "old" : null } }
The following example opens a transaction, updates an employee’s statusto Inactive
in the employees
status and inserts a correspondingdocument to the events
collection, and commits the two operationsas a single transaction.
- // Runs the txnFunc and retries if TransientTransactionError encountered
- function runTransactionWithRetry(txnFunc, session) {
- while (true) {
- try {
- txnFunc(session); // performs transaction
- break;
- } catch (error) {
- // If transient error, retry the whole transaction
- if ( error.hasOwnProperty("errorLabels") && error.errorLabels.includes("TransientTransactionError") ) {
- print("TransientTransactionError, retrying transaction ...");
- continue;
- } else {
- throw error;
- }
- }
- }
- }
- // Retries commit if UnknownTransactionCommitResult encountered
- function commitWithRetry(session) {
- while (true) {
- try {
- session.commitTransaction(); // Uses write concern set at transaction start.
- print("Transaction committed.");
- break;
- } catch (error) {
- // Can retry commit
- if (error.hasOwnProperty("errorLabels") && error.errorLabels.includes("UnknownTransactionCommitResult") ) {
- print("UnknownTransactionCommitResult, retrying commit operation ...");
- continue;
- } else {
- print("Error during commit ...");
- throw error;
- }
- }
- }
- }
- // Updates two collections in a transactions
- function updateEmployeeInfo(session) {
- employeesCollection = session.getDatabase("hr").employees;
- eventsCollection = session.getDatabase("reporting").events;
- session.startTransaction( { readConcern: { level: "snapshot" }, writeConcern: { w: "majority" } } );
- try{
- employeesCollection.updateOne( { employee: 3 }, { $set: { status: "Inactive" } } );
- eventsCollection.insertOne( { employee: 3, status: { new: "Inactive", old: "Active" } } );
- } catch (error) {
- print("Caught exception during transaction, aborting.");
- session.abortTransaction();
- throw error;
- }
- commitWithRetry(session);
- }
- // Start a session.
- session = db.getMongo().startSession( { readPreference: { mode: "primary" } } );
- try{
- runTransactionWithRetry(updateEmployeeInfo, session);
- } catch (error) {
- // Do something with error
- } finally {
- session.endSession();
- }
See also