Session.commitTransaction()
定义
Session.commitTransaction()
将操作所做的更改保存在多文档事务中并结束ACID 事务。
多文档事务适用于分片集群和副本集。
Session.commitTransaction()
不返回值。重要
mongosh 方法
本页面提供
mongosh
方法的相关信息。这不是数据库命令或特定语言驱动程序(例如 Node.js)的相关文档。有关数据库命令,请参阅
commitTransaction
命令。如需了解 MongoDB API 驱动程序,请参阅特定语言的 MongoDB 驱动程序文档。
行为
写关注
提交事务时,会话使用事务开始时指定的写关注。参见 Session.startTransaction()
。
原子性(Atomicity)
在事务提交时,事务中所做的所有数据更改都会保存,并且在事务之外可见。换言之,一个事务不会在回滚其他事务的同时提交某些更改。
在事务进行提交前,在事务中所做的数据更改在事务外不可见。
不过,当事务写入多个分片时,并非所有外部读取操作都需等待已提交事务的结果在各个分片上可见。例如,如果事务已提交并且写入 1 在分片 A 上可见,但写入 2 在分片 B 上尚不可见,则读关注 "local"
处的外部读取可以在不看到写入 2 的情况下读取写入 1 的结果。
可重试
如果提交操作遇到错误,无论是否将 retryWrites
设置为 false
,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" }
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 } }
以下示例将打开一个事务,在 employees
状态中将员工的状态更新为 Inactive
,将相应文档插入到 events
集合,并将这两个操作作为单个事务提交。
// 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; } } } } // 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(); }