Definition定义
Session.startTransaction(<options>)Starts a multi-document transaction associated with the session. At any given time, you can have at most one open transaction for a session.启动与会话关联的多文档事务。在任何给定时间,会话最多只能有一个打开的事务。Note
This operation is a no-op. The transaction won't start on the server until the first command is sent on the session. Therefore, the snapshot time of the transaction won't be set until the first command is sent on the session.此操作是无操作。在会话上发送第一个命令之前,事务不会在服务器上启动。因此,在会话上发送第一个命令之前,不会设置事务的快照时间。Multi-document transactions are available for both sharded clusters and replica sets.多文档事务可用于分片集群和副本集。Important
Within a transaction, you can only specify read and write (CRUD) operations on existing collections. For example, a multi-document transaction cannot include an insert operation that would result in the creation of a new collection.在事务中,您只能对现有集合指定读写(CRUD)操作。例如,多文档事务不能包含会导致创建新集合的插入操作。TheSession.startTransaction()method can take a document with the following options:Session.startTransaction()方法可以接受具有以下选项的文档:{ readConcern: { level: <level>}, writeConcern: { w: <value>, j: <boolean>, wtimeout: <number> } }Option选项Description描述readConcernOptional. A document that specifies the read concern for all operations in the transaction, overriding operation-specific read concern.可选。一个文档,指定事务中所有操作的读取关注,覆盖特定于操作的读取关心点。You can specify one of the following read concern levels:您可以指定以下读取关注级别之一:For对于"local"and"majority"read concern, MongoDB may sometimes substitute a stronger read concern."local"和"majority"读取关注,MongoDB有时可能会用更强的读取关注代替。writeConcernOptional. A document that specifies the write concern for the transaction. This write concern applies to the transaction commit and abort operations.可选。指定事务写入关注的文档。此写入关注适用于事务提交和中止操作。The operations within the transaction use事务中的操作使用"w: 1", overriding operation-specific write concern."w: 1",覆盖特定于操作的写入关注。If you commit using如果使用"w: 1"write concern, your transaction can be rolled back during the failover process."w: 1"写关注提交,则可以在故障转移过程中回滚事务。For MongoDB Drivers, transactions use the client-level write concern as the default.对于MongoDB驱动程序,事务使用客户端级写入关注作为默认值。
Compatibility兼容性
This method is available in deployments hosted in the following environments:此方法在以下环境中托管的部署中可用:
- MongoDB Atlas
: The fully managed service for MongoDB deployments in the cloud:云中MongoDB部署的完全托管服务
- MongoDB Enterprise
: The subscription-based, self-managed version of MongoDB:MongoDB的基于订阅的自我管理版本 - MongoDB Community
: The source-available, free-to-use, and self-managed version of MongoDB:MongoDB的源代码可用、免费使用和自我管理版本
Behavior行为
Operations Supported within a Transaction事务中支持的操作
Note
If running with access control, you must have privileges for the operations in the transaction.如果使用访问控制运行,则必须具有事务中操作的权限。
For multi-document transactions:对于多文档事务:
You can create collections and indexes in transactions. For details, see Create Collections and Indexes in a Transaction您可以在事务中创建集合和索引。有关详细信息,请参阅在事务中创建集合和索引The collections used in a transaction can be in different databases.事务中使用的集合可以在不同的数据库中。Note
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无法在同一事务中执行这两个操作。You cannot write to capped collections.您不能写入封顶集合。You cannot use read concern从封顶集合中读取时,不能使用读取关注"snapshot"when reading from a capped collection. (Starting in MongoDB 5.0)"snapshot"。(从MongoDB 5.0开始)You cannot read/write to collections in the您无法对config,admin, orlocaldatabases.config、admin或local数据库中的集合进行读写操作。You cannot write to您无法写入system.*collections.system.*集合。You cannot return the supported operation's query plan using您无法使用explainor similar commands.explain或类似命令返回受支持操作的查询计划。
For cursors created outside of a transaction, you cannot call对于在事务外部创建的游标,您不能在事务内部调用getMoreinside the transaction.getMore。For cursors created in a transaction, you cannot call对于在事务中创建的游标,您不能在事务外部调用getMoreoutside the transaction.getMore。
You cannot specify the不能将killCursorscommand as the first operation in a transaction.killCursors命令指定为事务中的第一个操作。Additionally, if you run the此外,如果在事务中运行killCursorscommand within a transaction, the server immediately stops the specified cursors. It does not wait for the transaction to commit.killCursors命令,服务器会立即停止指定的游标。它不会等待事务提交。
db.collection.aggregate() | aggregate |
|
db.collection.countDocuments() |
| |
db.collection.distinct() | distinct |
|
db.collection.find() | find | |
db.collection.deleteMany()db.collection.deleteOne()db.collection.remove() | delete | |
db.collection.findOneAndDelete()db.collection.findOneAndReplace()db.collection.findOneAndUpdate() | findAndModify |
|
db.collection.insertMany()db.collection.insertOne() | insert |
|
db.collection.updateOne()db.collection.updateMany()db.collection.replaceOne() | update |
|
db.collection.bulkWrite() |
|
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(及其辅助方法);但是,它们不能是事务中的第一个操作。
Read Preference读取首选项
Transactions support read preference 事务支持读取首选项primary.primary。
Atomicity原子性
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。When a transaction aborts, all data changes made by the writes in the transaction are discarded without ever becoming visible and the transaction ends.当事务中止时,事务中写入所做的所有数据更改都将被丢弃,不再可见,事务结束。
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. 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?.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();
}