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(); }