Session.abortTransaction()
定义
Session.abortTransaction()
终止多文档事务,并回滚ACID 事务中操作所做的任何数据更改。 也就是说,ACID 事务结束时不保存ACID 事务中操作所做的任何更改。
多文档事务适用于分片集群和副本集。
Session.abortTransaction()
不返回值。重要
mongosh 方法
本页面提供
mongosh
方法的相关信息。这不是数据库命令或特定语言驱动程序(例如 Node.js)的相关文档。有关数据库命令,请参阅
abortTransaction
命令。如需了解 MongoDB API 驱动程序,请参阅特定语言的 MongoDB 驱动程序文档。
行为
原子性(Atomicity)
当事务中止时,事务中通过写入进行的所有数据更改都会丢弃且变得不可见,同时事务结束。
安全性
如果以审核方式运行,中止的事务中的操作仍会被审核。
可重试
如果中止操作遇到错误,无论是否将 retryWrites
设置为 true
,MongoDB 驱动程序都会重试一次中止操作。有关详细信息,请参阅事务错误处理。
例子
考虑这样一种情况:当对 hr
数据库中的员工记录进行更改时,您希望确保 reporting
数据库中的 events
集合与 hr
更改同步。换言之,您希望确保这些写入作为单个事务完成,以便两个操作要么成功,要么失败。
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" }
employees
集合具有针对 employee
字段的唯一复合索引:
db.employees.createIndex( { employee: 1 }, { unique: true } )
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 } }
以下示例打开一个事务,尝试将记录添加到 events
集合并将文档添加到 employees
集合。如果操作在操作或提交事务时遇到错误,会话将中止事务。
// 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?.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?.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(); }