文档菜单
文档首页
/ / /
Node.js 驱动
/

事务

本页内容

  • 概述
  • 事务API
  • 核心API
  • 便捷交易API
  • 交易选项
  • 交易错误

在本指南中,您可以学习如何使用Node.js驱动程序执行交易。交易允许您运行一系列操作,直到整个交易提交之前不会更改任何数据。如果交易中的任何操作失败,驱动程序将结束交易并丢弃所有数据更改,这些更改永远不会变得可见。此功能称为原子性

由于MongoDB中单个文档上的所有写操作都是原子的,您可能想使用交易来执行修改多个文档的原子更改。这种情况需要多文档交易。多文档交易是ACID兼容的,因为MongoDB保证您交易操作涉及的数据保持一致性,即使驱动程序遇到意外的错误。

有关ACID兼容性和交易的更多信息,请参阅我们关于ACID交易的文章.

注意

要执行多文档交易,您必须连接到运行MongoDB服务器版本4.0或更高版本的部署。

有关限制的详细列表,请参阅服务器手册中的交易和操作部分。

在MongoDB中,多文档交易在客户端会话中运行。客户端会话是您希望顺序执行的关联读取或写入操作的分组。我们建议您重用客户端进行多个会话和交易,而不是每次都实例化一个新的客户端。

当与majority读取和写入关注点结合使用时,驱动程序保证了操作之间的因果关系一致性。有关更多信息,请参阅服务器手册中的客户端会话和因果关系保证部分。

有关如何使用驱动程序执行多文档交易的更多信息,请参阅本指南的以下部分

该驱动程序提供了两个用于执行事务的API,即核心API便捷事务API

核心API是一个框架,允许您创建、提交和结束事务。在使用此API时,您必须显式执行以下操作

  • 创建、提交和结束事务。

  • 创建和结束执行事务的会话。

  • 实现错误处理逻辑。

便捷事务API是一个框架,允许您在不负责提交或结束事务的情况下执行事务。此API自动集成错误处理逻辑,在服务器抛出某些错误类型时自动重试操作。有关此行为的更多信息,请参阅本指南的事务错误部分。

重要

当您连接到MongoDB服务器版本4.2或更早版本时,您只能在已存在的集合上执行事务写入操作。当您连接到MongoDB服务器版本4.4及更高版本时,服务器在您执行事务写入操作时自动根据需要创建集合。有关此行为的更多信息,请参阅服务器手册中的在事务中创建集合和索引部分。

核心API提供了以下方法来实现事务

在使用此API时,您必须执行以下步骤

  • 将会话实例传递给要在该会话中运行的每个操作。

  • 实现一个catch块,用于识别服务器事务错误并实现错误处理逻辑。

以下代码演示了如何使用核心API执行事务

async function coreTest(client) {
const session = client.startSession();
try {
session.startTransaction();
const savingsColl = client.db("bank").collection("savings_accounts");
await savingsColl.findOneAndUpdate(
{account_id: "9876"},
{$inc: {amount: -100 }},
{ session });
const checkingColl = client.db("bank").collection("checking_accounts");
await checkingColl.findOneAndUpdate(
{account_id: "9876"},
{$inc: {amount: 100 }},
{ session });
// ... perform other operations
await session.commitTransaction();
console.log("Transaction committed.");
} catch (error) {
console.log("An error occurred during the transaction:" + error);
await session.abortTransaction();
} finally {
await session.endSession();
}
}

重要

使用启动会话的客户端进行会话

如果将一个MongoClient实例的会话提供给不同的客户端实例,驱动程序会抛出一个错误。

例如,以下代码会生成一个MongoInvalidArgumentError错误,因为它从client1客户端创建了一个ClientSession实例,但将此会话提供给client2客户端进行写操作

const session = client1.startSession();
client2.db('myDB').collection('myColl').insertOne({ name: 'Jane Eyre' }, { session });

要查看使用此API的完整可运行示例,请参阅使用核心API使用示例。

便捷事务API提供了以下方法来实现事务

  • withSession():在会话中运行传递给它的回调函数。API自动处理会话的创建和终止。

  • withTransaction():在事务中运行传递给它的回调函数,并在回调函数返回时调用commitTransaction()方法。

这些方法返回回调函数返回的值。例如,如果您将文档{ hello: "world" }传递给withTransaction()方法,那么withTransaction()方法也返回该文档。

重要

为了避免无限循环错误,请确保传递给withTransaction()方法的回调函数捕获它引发的任何错误。

当您使用方便的事务API时,可以将回调函数的返回值传播为withTransaction()withSession()方法的返回值,以便在代码的其他部分中使用它们。

在使用此API时,您必须执行以下步骤

  • 将会话实例传递给要在该会话中运行的每个操作。

  • 在会话中的每个操作中都实现异步await语法。

  • 避免并行执行,例如调用Promise.all()方法。通常,并行使用会话会导致服务器错误。

以下代码演示了如何使用方便的事务API执行事务

async function convTest(client) {
let txnRes = await client.withSession(async (session) =>
session.withTransaction(async (session) => {
const savingsColl = client.db("bank").collection("savings_accounts");
await savingsColl.findOneAndUpdate(
{account_id: "9876"},
{$inc: {amount: -100 }},
{ session });
const checkingColl = client.db("bank").collection("checking_accounts");
await checkingColl.findOneAndUpdate(
{account_id: "9876"},
{$inc: {amount: 100 }},
{ session });
// ... perform other operations
return "Transaction committed.";
}, null)
);
console.log(txnRes);
}

要查看使用此API的完整可运行示例,请参阅使用方便的事务API使用示例。

您可以将一个 TransactionOptions 实例传递给 startTransaction()withTransaction() 方法来配置驱动程序执行事务的方式。当您指定一个选项时,它将覆盖您可能在 MongoClient 实例上设置的选项值。

下表包含您可以在 TransactionOptions 实例中指定的选项

设置
描述
readConcern
指定副本集的读取操作一致性。
有关更多信息,请参阅服务器手册中的读取关注
writeConcern
指定从副本集获取写入操作确认所需的级别。
有关更多信息,请参阅服务器手册中的写入关注
readPreference
指定如何将读取操作路由到副本集的成员。
有关更多信息,请参阅服务器手册中的读取偏好
maxCommitTimeMS
指定事务提交操作可以运行的时间长度,以毫秒为单位。

有关选项的完整列表,请参阅TransactionOptions 的API文档。

注意

除非您在事务选项中指定它们,否则事务将从您的 MongoClient 实例继承设置。

以下代码演示了如何定义和传递事务选项给 startTransaction() 方法

const txnOpts = {
readPreference: 'primary',
readConcern: { level: 'local' },
writeConcern: { w: 'majority' },
maxCommitTimeMS: 1000
};
session.startTransaction(txnOpts);

如果您正在使用 Core API 来执行事务,您必须将错误处理逻辑整合到您的应用程序中,以处理以下错误

  • TransientTransactionError:如果在驱动程序提交事务之前写入操作出错,则会抛出此错误。有关此错误的更多信息,请参阅服务器手册中驱动程序 API 页面上的 TransientTransactionError 描述

  • UnknownTransactionCommitResult:如果在提交操作中遇到错误,则会抛出此错误。有关此错误的更多信息,请参阅服务器手册中驱动程序 API 页面上的 UnknownTransactionCommitResult 描述

方便的事务 API 集成了这些错误类型的重试逻辑,因此驱动程序将重试事务,直到成功提交。

返回

聚合