Docs HomeMongoDB Manual

Drivers API驱动程序API

Callback API vs Core API

The Callback API:回调API

The Core API:核心API

Callback API

The callback API incorporates logic:回调API包含以下逻辑:

Starting in MongoDB 6.2, the server does not retry the transaction if it receives a TransactionTooLargeForCache error.从MongoDB 6.2开始,如果服务器收到TransactionTooLargeForCache错误,则不会重试该事务。

Example实例


➤ Use the Select your language drop-down menu in the upper-right to set the language of the examples on this page.


Important
  • Recommended. Use the MongoDB driver updated for the version of your MongoDB deployment. 推荐。使用为您的MongoDB部署版本更新的MongoDB驱动程序。For transactions on MongoDB 4.2 deployments (replica sets and sharded clusters), clients must use MongoDB drivers updated for MongoDB 4.2.对于MongoDB 4.2部署上的事务(副本集和分片集群),客户端必须使用为MongoDB 4.2更新的MongoDB驱动程序。

  • When using the drivers, each operation in the transaction must be associated with the session (i.e. pass in the session to each operation).使用驱动程序时,事务中的每个操作都必须与会话相关联(即,将会话传递给每个操作)。

  • Operations in a transaction use transaction-level read concern, transaction-level write concern, and transaction-level read preference.事务中的操作使用事务级读取关注事务级写入关注事务级读取首选项

  • In MongoDB 4.2 and earlier, you cannot create collections in transactions. 在MongoDB 4.2及更早版本中,您不能在事务中创建集合。Write operations that result in document inserts (e.g. insert or update operations with upsert: true) must be on existing collections if run inside transactions.如果在事务内部运行,则导致文档插入的写入操作(例如,插入或使用upsert:true的更新操作)必须在现有集合上。

  • Starting in MongoDB 4.4, you can create collections in transactions implicitly or explicitly. See Create Collections and Indexes In a Transaction.从MongoDB 4.4开始,您可以隐式或显式地在事务中创建集合。请参见在事务中创建集合和索引

The example uses the new callback API for working with transactions, which starts a transaction, executes the specified operations, and commits (or aborts on error). 该示例使用新的回调API处理事务,启动事务、执行指定的操作并提交(或在出现错误时中止)。The new callback API incorporates retry logic for TransientTransactionError or UnknownTransactionCommitResult commit errors.新回调API包含TransientTransactionErrorUnknownTransactionCommitResult提交错误的重试逻辑。

  // For a replica set, include the replica set name and a seedlist of the members in the URI string; 对于副本集,在URI字符串中包括副本集名称和成员的种子列表;e.g.
// const uri = 'mongodb://mongodb0.example.com:27017,mongodb1.example.com:27017/?replicaSet=myRepl'
// For a sharded cluster, connect to the mongos instances; 对于分片集群,连接到mongos实例;e.g.
// const uri = 'mongodb://mongos0.example.com:27017,mongos1.example.com:27017/'

const client = new MongoClient(uri);
await client.connect();

// Prereq: Create collections.准备工作:创建集合。

await client
.db('mydb1')
.collection('foo')
.insertOne({ abc: 0 }, { writeConcern: { w: 'majority' } });

await client
.db('mydb2')
.collection('bar')
.insertOne({ xyz: 0 }, { writeConcern: { w: 'majority' } });

// Step 1: Start a Client Session步骤1:启动客户端会话
const session = client.startSession();

// Step 2: Optional. Define options to use for the transaction步骤2:可选。定义用于事务的选项
const transactionOptions = {
readPreference: 'primary',
readConcern: { level: 'local' },
writeConcern: { w: 'majority' }
};

// Step 3: Use withTransaction to start a transaction, execute the callback, and commit (or abort on error)步骤3:使用withTransaction启动事务、执行回调并提交(或在出现错误时中止)
// Note: The callback for withTransaction MUST be async and/or return a Promise.注意:withTransaction的回调必须是异步的和/或返回Promise。
try {
await session.withTransaction(async () => {
const coll1 = client.db('mydb1').collection('foo');
const coll2 = client.db('mydb2').collection('bar');

// Important:: You must pass the session to the operations重要提示:您必须将会话传递给操作

await coll1.insertOne({ abc: 1 }, { session });
await coll2.insertOne({ xyz: 999 }, { session });
}, transactionOptions);
} finally {
await session.endSession();
await client.close();
}

Core API

The core transaction API does not incorporate retry logic for errors labeled:核心事务API不包含标记为以下错误的重试逻辑:

Example实例


➤ Use the Select your language drop-down menu in the upper-right to set the language of the examples on this page.


The following example incorporates logic to retry the transaction for transient errors and retry the commit for unknown commit error:以下示例包含了针对暂时错误重试事务和针对未知提交错误重试提交的逻辑:

Important

To associate read and write operations with a transaction, you must pass the session to each operation in the transaction.要将读写操作与事务相关联,必须将会话传递给事务中的每个操作。

async function commitWithRetry(session) {
try {
await session.commitTransaction();
console.log('Transaction committed.');
} catch (error) {
if (error.hasErrorLabel('UnknownTransactionCommitResult')) {
console.log('UnknownTransactionCommitResult, retrying commit operation ...');
await commitWithRetry(session);
} else {
console.log('Error during commit ...');
throw error;
}
}
}

async function runTransactionWithRetry(txnFunc, client, session) {
try {
await txnFunc(client, session);
} catch (error) {
console.log('Transaction aborted. Caught exception during transaction.');

// If transient error, retry the whole transaction如果出现暂时错误,请重试整个事务
if (error.hasErrorLabel('TransientTransactionError')) {
console.log('TransientTransactionError, retrying transaction ...');
await runTransactionWithRetry(txnFunc, client, session);
} else {
throw error;
}
}
}

async function updateEmployeeInfo(client, session) {
session.startTransaction({
readConcern: { level: 'snapshot' },
writeConcern: { w: 'majority' },
readPreference: 'primary'
});

const employeesCollection = client.db('hr').collection('employees');
const eventsCollection = client.db('reporting').collection('events');

await employeesCollection.updateOne(
{ employee: 3 },
{ $set: { status: 'Inactive' } },
{ session }
);
await eventsCollection.insertOne(
{
employee: 3,
status: { new: 'Inactive', old: 'Active' }
},
{ session }
);

try {
await commitWithRetry(session);
} catch (error) {
await session.abortTransaction();
throw error;
}
}

return client.withSession(session =>
runTransactionWithRetry(updateEmployeeInfo, client, session)
);

Driver Versions驱动程序版本

For transactions on MongoDB 4.2 deployments (replica sets and sharded clusters), clients must use MongoDB drivers updated for MongoDB 4.2:对于MongoDB 4.2部署上的事务(副本集和分片集群),客户端必须使用为MongoDB 4.2更新的MongoDB驱动程序:

Transaction Error Handling事务错误处理

Regardless of the database system, whether MongoDB or relational databases, applications should take measures to handle errors during transaction commits and incorporate retry logic for transactions.无论数据库系统是MongoDB还是关系数据库,应用程序都应该采取措施来处理事务提交过程中的错误,并为事务引入重试逻辑。

TransientTransactionError

The individual write operations inside the transaction are not retryable, regardless of the value of retryWrites. 无论retryWrites的值如何,事务中的各个写入操作都是不可重试的。If an operation encounters an error associated with the label "TransientTransactionError", such as when the primary steps down, the transaction as a whole can be retried.如果操作遇到与标签"TransientTransactionError"相关联的错误,例如当主操作停止时,则可以重试整个事务。

  • The callback API incorporates retry logic for "TransientTransactionError".回调API包含"TransientTransactionError"的重试逻辑。
  • The core transaction API does not incorporate retry logic for "TransientTransactionError". 核心事务API未包含"TransientTransactionError"的重试逻辑。To handle "TransientTransactionError", applications should explicitly incorporate retry logic for the error.为了处理"TransientTransactionError",应用程序应该明确地包含错误的重试逻辑。

UnknownTransactionCommitResult

The commit operations are retryable write operations. 提交操作是可重试的写入操作If the commit operation encounters an error, MongoDB drivers retry the commit regardless of the value of retryWrites.如果提交操作遇到错误,MongoDB驱动程序将重试提交,而不考虑retryWrites的值。

If the commit operation encounters an error labeled "UnknownTransactionCommitResult", the commit can be retried.如果提交操作遇到标记为"UnknownTransactionCommitResult"的错误,则可以重试提交。

  • The callback API incorporates retry logic for "UnknownTransactionCommitResult".回调API包含"UnknownTransactionCommitResult"的重试逻辑。
  • The core transaction API does not incorporate retry logic for "UnknownTransactionCommitResult". To handle "UnknownTransactionCommitResult", applications should explicitly incorporate retry logic for the error.

TransactionTooLargeForCache

New in version 6.2. 6.2版新增。

Starting in MongoDB 6.2, the server does not retry the transaction if it receives a TransactionTooLargeForCache error. 从MongoDB 6.2开始,如果服务器收到TransactionTooLargeForCache错误,则不会重试该事务。This error means the cache is too small and a retry is likely to fail.此错误意味着缓存太小,重试可能会失败。

The default value for the transactionTooLargeForCacheThreshold threshold is 0.75. transactionTooLargeForCacheThreshold阈值的默认值为0.75The server returns TransactionTooLargeForCache instead of retrying the transaction when the transaction uses more than 75% of the cache.当事务使用超过75%的缓存时,服务器返回TransactionTooLargeForCache,而不是重试该事务。

In earlier versions of MongoDB, the server returns TemporarilyUnavailable or WriteConflict instead of TransactionTooLargeForCache.在早期版本的MongoDB中,服务器返回TemporarilyUnavailableWriteConflict,而不是TransactionTooLargeForCache

Use the setParameter command to modify the error threshold.使用setParameter命令可以修改错误阈值。

Driver Version Errors驱动程序版本错误

On sharded clusters with multiple mongos instances, performing transactions with drivers updated for MongoDB 4.0 (instead of MongoDB 4.2) will fail and can result in errors, including:在具有多个mongos实例的分片集群上,使用为MongoDB 4.0(而不是MongoDB 4.2)更新的驱动程序执行事务将失败,并可能导致错误,包括:

Note

Your driver may return a different error. 您的驱动程序可能会返回不同的错误。Refer to your driver's documentation for details.有关详细信息,请参阅您的驾驶员文档。

Error Code错误代码Error Message错误消息
251cannot continue txnId -1 for session ... with txnId 1
50940cannot commit with no participants

For transactions on MongoDB 4.2 deployments (replica sets and sharded clusters), use the MongoDB drivers updated for MongoDB 4.2对于MongoDB 4.2部署上的事务(副本集和分片集群),请使用为MongoDB 4.2更新的MongoDB驱动程序

Additional Information附加信息

mongosh Example实例

The following mongosh methods are available for transactions:以下mongosh方法可用于事务:

Note

The mongosh example omits retry logic and robust error handling for simplicity's sake. 为了简单起见,mongosh示例省略了重试逻辑和健壮的错误处理。For a more practical example of incorporating transactions in applications, see Transaction Error Handling instead.有关在应用程序中合并事务的更实用的示例,请参阅事务错误处理

// Create collections:创建集合:
db.getSiblingDB("mydb1").foo.insertOne(
{abc: 0},
{ writeConcern: { w: "majority", wtimeout: 2000 } }
)
db.getSiblingDB("mydb2").bar.insertOne(
{xyz: 0},
{ writeConcern: { w: "majority", wtimeout: 2000 } }
)

// Start a session.启动会话。
session = db.getMongo().startSession( { readPreference: { mode: "primary" } } );

coll1 = session.getDatabase("mydb1").foo;
coll2 = session.getDatabase("mydb2").bar;

// Start a transaction启动事务
session.startTransaction( { readConcern: { level: "local" }, writeConcern: { w: "majority" } } );

// Operations inside the transaction事务内部的操作
try {
coll1.insertOne( { abc: 1 } );
coll2.insertOne( { xyz: 999 } );
} catch (error) {
// Abort transaction on error
session.abortTransaction();
throw error;
}

// Commit the transaction using write concern set at transaction start在事务开始时使用写关注点集提交事务
session.commitTransaction();

session.endSession();