Session.abortTransaction()

Definition

  • Session.abortTransaction()

New in version 4.0.

Terminates the multi-document transaction and rolls back any data changes made by theoperations within the transaction. That is, the transaction endswithout saving any of the changes made by the operations in thetransaction.

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

Atomicity

When a transaction aborts, all data changes made by the writes in thetransaction are discarded without ever becoming visible and thetransaction ends.

Security

If running with auditing, operations in anaborted transaction are still audited.

Retryable

If the abort operation encounters an error, MongoDB drivers retry theabort operation a single time regardless of whetherretryWrites is set to true. 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 eventscollection in the reporting database are in sync with the hrchanges and vice versa. 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:

  1. { "_id" : ObjectId("5af0776263426f87dd69319a"), "employee" : 3, "name" : { "title" : "Mr.", "name" : "Iba Ochs" }, "status" : "Active", "department" : "ABC" }
  2. { "_id" : ObjectId("5af0776263426f87dd693198"), "employee" : 1, "name" : { "title" : "Miss", "name" : "Ann Thrope" }, "status" : "Active", "department" : "ABC" }
  3. { "_id" : ObjectId("5af0776263426f87dd693199"), "employee" : 2, "name" : { "title" : "Mrs.", "name" : "Eppie Delta" }, "status" : "Active", "department" : "XYZ" }

The employees collection has a unique index on the employee field:

  1. db.employees.createIndex( { employee: 1 }, { unique: true } )

The events collection in the reporting database has thefollowing documents:

  1. { "_id" : ObjectId("5af07daa051d92f02462644a"), "employee" : 1, "status" : { "new" : "Active", "old" : null }, "department" : { "new" : "ABC", "old" : null } }
  2. { "_id" : ObjectId("5af07daa051d92f02462644b"), "employee" : 2, "status" : { "new" : "Active", "old" : null }, "department" : { "new" : "XYZ", "old" : null } }
  3. { "_id" : ObjectId("5af07daa051d92f02462644c"), "employee" : 3, "status" : { "new" : "Active", "old" : null }, "department" : { "new" : "ABC", "old" : null } }

The following example opens a transaction, attempts to add a record tothe events collection and add a document to the employeescollection. If the operation encounters an error in either operationsor in committing the transaction, the session aborts the transaction.

  1. // Runs the txnFunc and retries if TransientTransactionError encountered
  2.  
  3. function runTransactionWithRetry(txnFunc, session) {
  4. while (true) {
  5. try {
  6. txnFunc(session); // performs transaction
  7. break;
  8. } catch (error) {
  9. // If transient error, retry the whole transaction
  10. if ( error.hasOwnProperty("errorLabels") && error.errorLabels.includes("TransientTransactionError") ) {
  11. print("TransientTransactionError, retrying transaction ...");
  12. continue;
  13. } else {
  14. throw error;
  15. }
  16. }
  17. }
  18. }
  19.  
  20. // Retries commit if UnknownTransactionCommitResult encountered
  21.  
  22. function commitWithRetry(session) {
  23. while (true) {
  24. try {
  25. session.commitTransaction(); // Uses write concern set at transaction start.
  26. print("Transaction committed.");
  27. break;
  28. } catch (error) {
  29. // Can retry commit
  30. if (error.hasOwnProperty("errorLabels") && error.errorLabels.includes("UnknownTransactionCommitResult") ) {
  31. print("UnknownTransactionCommitResult, retrying commit operation ...");
  32. continue;
  33. } else {
  34. print("Error during commit ...");
  35. throw error;
  36. }
  37. }
  38. }
  39. }
  40.  
  41. // Performs inserts and count in a transaction
  42. function updateEmployeeInfo(session) {
  43. employeesCollection = session.getDatabase("hr").employees;
  44. eventsCollection = session.getDatabase("reporting").events;
  45.  
  46. // Start a transaction for the session that uses:
  47. // - read concern "snapshot"
  48. // - write concern "majority"
  49.  
  50. session.startTransaction( { readConcern: { level: "snapshot" }, writeConcern: { w: "majority" } } );
  51.  
  52. try{
  53. eventsCollection.insertOne(
  54. { employee: 3, status: { new: "Active", old: null }, department: { new: "XYZ", old: null } }
  55. );
  56.  
  57. // Count number of events for employee 3
  58.  
  59. var countDoc = eventsCollection.aggregate( [ { $match: { employee: 3 } }, { $count: "eventCounts" } ] ).next();
  60.  
  61. print( "events count (in active transaction): " + countDoc.eventCounts );
  62.  
  63. // The following operations should fail as an employee ``3`` already exist in employees collection
  64. employeesCollection.insertOne(
  65. { employee: 3, name: { title: "Miss", name: "Terri Bachs" }, status: "Active", department: "XYZ" }
  66. );
  67. } catch (error) {
  68. print("Caught exception during transaction, aborting.");
  69. session.abortTransaction();
  70. throw error;
  71. }
  72.  
  73. commitWithRetry(session);
  74.  
  75. } // End of updateEmployeeInfo function
  76.  
  77. // Start a session.
  78. session = db.getMongo().startSession( { readPreference: { mode: "primary" } } );
  79.  
  80. try{
  81. runTransactionWithRetry(updateEmployeeInfo, session);
  82. } catch (error) {
  83. // Do something with error
  84. } finally {
  85. session.endSession();
  86. }

See also