Session.abortTransaction()

On this page本页内容

Definition定义

Session.abortTransaction()

New in version 4.0.在版本4.0中新增

Terminates the multi-document transaction and rolls back any data changes made by the operations within the transaction. 终止多文档事务,并回滚事务中操作所做的任何数据更改。That is, the transaction ends without saving any of the changes made by the operations in the transaction.也就是说,事务结束时不保存事务中操作所做的任何更改。

Note注意
Availability可用性
  • 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引入了分布式事务,它增加了对分片集群上多文档事务的支持,并合并了对副本集上多文档事务的现有支持。

Behavior行为

Atomicity原子性

When a transaction aborts, all data changes made by the writes in the transaction are discarded without ever becoming visible and the transaction ends.当事务中止时,事务中写入的所有数据更改将被丢弃,而不会变得可见,事务结束。

Security安全

If running with auditing, operations in an aborted transaction are still audited.如果使用审核运行,则仍将审核中止事务中的操作。

Retryable可重试

If the abort operation encounters an error, MongoDB drivers retry the abort operation a single time regardless of whether retryWrites is set to true. 如果中止操作遇到错误,MongoDB驱动程序将重试中止操作一次,无论retryWrites是否设置为trueFor more information, see Transaction Error Handling.有关详细信息,请参阅事务错误处理

Example示例

Consider a scenario where as changes are made to an employee's record in the hr database, you want to ensure that the events collection in the reporting database are in sync with the hr changes and vice versa. 考虑这样一个场景:当对hr数据库中的员工记录进行更改时,您希望确保reporting数据库中的events集合与人力资源更改同步,反之亦然。That is, you want to ensure that these writes are done as a single transaction, such that either both operations succeed or fail.也就是说,您希望确保这些写操作作为单个事务完成,以便两个操作都成功或失败。

The employees collection in the hr database has the following documents:hr数据库中的employees集合包含以下文档:

{ "_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 employees collection has a unique index on the employee field:employees集合在employee字段上具有唯一索引:

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

The events collection in the reporting database has the following documents:reporting数据库中的events集合包含以下文档:

{ "_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, attempts to add a record to the events collection and add a document to the employees collection. 以下示例打开事务,尝试将记录添加到events集合,并将文档添加到employees集合。If the operation encounters an error in either operations or in committing the transaction, the session aborts the 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;
            }
       }
    }
}
// Performs inserts and count in a transaction
function updateEmployeeInfo(session) {
   employeesCollection = session.getDatabase("hr").employees;
   eventsCollection = session.getDatabase("reporting").events;
   // Start a transaction for the session that uses:
   // - read concern "snapshot"
   // - write concern "majority"
   session.startTransaction( { readConcern: { level: "snapshot" }, writeConcern: { w: "majority" } } );
   try{
      eventsCollection.insertOne(
         { employee: 3, status: { new: "Active", old: null },  department: { new: "XYZ", old: null } }
      );
      // Count number of events for employee 3
      var countDoc = eventsCollection.aggregate( [ { $match:  { employee: 3 } }, { $count: "eventCounts" } ] ).next();
      print( "events count (in active transaction): " + countDoc.eventCounts );
      // The following operations should fail as an employee ``3`` already exist in employees collection
      employeesCollection.insertOne(
         { employee: 3, name: { title: "Miss", name: "Terri Bachs" }, status: "Active", department: "XYZ" }
      );
   } catch (error) {
      print("Caught exception during transaction, aborting.");
      session.abortTransaction();
      throw error;
   }
   commitWithRetry(session);
} // End of updateEmployeeInfo function
// Start a session.
session = db.getMongo().startSession( { readPreference: { mode: "primary" } } );
try{
   runTransactionWithRetry(updateEmployeeInfo, session);
} catch (error) {
   // Do something with error
} finally {
   session.endSession();
}
←  SessionSession.commitTransaction() →