On this page本页内容
Session.startTransaction(<options>)
New in version 4.0.在版本4.0中新增。
Starts a multi-document transaction associated with the session. 启动与会话关联的多文档事务。At any given time, you can have at most one open transaction for a session.在任何给定时间,一个会话最多只能有一个打开的事务。
Within a transaction, you can only specify read and write (CRUD) operations on existing collections. 在事务中,只能对现有集合指定读写(CRUD)操作。For example, a multi-document transaction cannot include an insert operation that would result in the creation of a new collection.例如,多文档事务不能包含导致创建新集合的插入操作。
The Session.startTransaction() method can take a document following options:Session.startTransaction()方法可以采用以下选项的文档:
{ readConcern: { level: <level>}, writeConcern: { w: <value>, j: <boolean>, wtimeout: <number> } }
readConcern |
|
writeConcern |
|
If running with access control, you must have privileges for the operations in the transaction.如果使用访问控制运行,则必须对事务中的操作具有权限。
For multi-document transactions:对于多文档事务处理:
The collections used in a transaction can be in different databases.事务中使用的集合可以位于不同的数据库中。
You cannot create new collections in cross-shard write transactions. 不能在跨分片写入事务中创建新集合。For example, if you write to an existing collection in one shard and implicitly create a collection in a different shard, MongoDB cannot perform both operations in the same transaction.例如,如果写入一个分片中的现有集合,并在另一个分片中隐式创建一个集合,则MongoDB无法在同一事务中同时执行这两个操作。
"snapshot" when reading from a capped collection. (Starting in MongoDB 5.0)"snapshot"。(从MongoDB 5.0开始)config, admin, or local databases.config、admin或local数据库中的集合。system.* collections.system.*集合。explain).explain)。getMore inside the transaction.getMore。getMore outside the transaction.getMore。killCursors as the first operation in a transaction.killCursors指定为事务中的第一个操作。db.collection.aggregate() | aggregate |
|
db.collection.countDocuments() |
| |
db.collection.distinct() | distinct |
$group stage. $group阶段的聚合管道。Distinct操作。 |
db.collection.find() | find | |
delete | ||
findAndModify |
| |
insert |
| |
update |
| |
|
Operations that affect the database catalog, such as creating or dropping a collection or an index, are not allowed in multi-document transactions. 在多文档事务中不允许执行影响数据库目录的操作,例如创建或删除集合或索引。For example, a multi-document transaction cannot include an insert operation that would result in the creation of a new collection. 例如,多文档事务不能包含导致创建新集合的插入操作。See Restricted Operations.请参阅受限操作。
Informational commands, such as 事务中允许使用hello, buildInfo, connectionStatus (and their helper methods) are allowed in transactions; however, they cannot be the first operation in the transaction.hello、buildInfo、connectionStatus等信息命令(及其助手方法);然而,它们不能是事务中的第一个操作。
Transactions support read preference 事务支持读取首选项primary.primary。
While the transaction is open, no data changes made by operations in the transaction is visible outside the transaction:当事务处于打开状态时,在事务外部看不到事务中操作所做的数据更改:
When a transaction commits, all data changes made in the transaction are saved and visible outside the transaction. 当事务提交时,事务中所做的所有数据更改都将保存并在事务外部可见。That is, a transaction will not commit some of its changes while rolling back others.也就是说,事务不会提交其某些更改,而回滚其他更改。
Until a transaction commits, the data changes made in the transaction are not visible outside the transaction.在事务提交之前,在事务中所做的数据更改在事务外部不可见。
However, when a transaction writes to multiple shards, not all outside read operations need to wait for the result of the committed transaction to be visible across the shards. 然而,当事务写入多个分片时,并非所有外部读取操作都需要等待提交的事务的结果在分片中可见。For example, if a transaction is committed and write 1 is visible on shard A but write 2 is not yet visible on shard B, an outside read at read concern 例如,如果事务已提交,并且写1在分片a上可见,但写2在分片B上尚不可见,则外部读取关注点"local" can read the results of write 1 without seeing write 2."local"可以读取写1的结果,而不会看到写2。
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. hr数据库中的员工记录进行更改时,您希望确保reporting数据库中的events集合与hr更改同步。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 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, updates an employee's status to 以下示例打开一个事务,在Inactive in the employees status and inserts a corresponding document to the events collection, and commits the two operations as a single transaction.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.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(); }