“文档” 菜单
文档首页
/ / /
Node.js 驱动程序
/

事务

在此页面上

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

在本指南中,您可以了解如何使用 Node.js 驱动程序执行事务。事务允许您运行一系列操作,这些操作在提交整个事务之前不会更改任何数据。如果事务中的任何操作失败,驱动程序就会结束事务,并在所有数据更改变得可见之前予以丢弃。这种特征称为原子性

由于 MongoDB 中对单个文档进行的所有写操作都是原子操作,因此您可能希望使用事务来进行修改多个文档的原子更改。这种情况需要进行多文档事务。多文档事务符合 ACID,因为 MongoDB 会为您的事务操作中涉及的数据保证一致性,即使驱动程序遇到意外错误。

要了解有关 ACID 合规性和事务的更多信息,请参阅我们关于 ACID 事务的文章。

注意

要执行多文档事务,必须连接到运行 MongoDB Server 4.0 或更高版本的部署。

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

在 MongoDB 中,多文档事务在客户端会话中运行。客户端会话是要按顺序执行的一组相关读取或写入操作。我们建议您将客户端重复用于多个会话和事务,而不是每次都实例化一个新客户端。

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

有关如何使用驱动程序执行多文档事务的更多信息,请参阅本指南的以下章节:

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

借助 Core API 框架,您可以创建、提交和结束事务。使用该 API 时,必须显式执行以下操作:

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

  • 创建并结束运行事务的会话。

  • 实施错误处理逻辑。

借助便捷事务 API 框架,您能够执行事务,而无需负责提交或结束事务。当服务器引发某些错误类型时,该 API 会自动纳入错误处理逻辑以重新尝试操作。如需有关此行为的更多信息,请参阅本指南的“事务错误”部分。

重要

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

Core API 提供以下方法来执行事务:

使用该 API 时,必须执行以下步骤:

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

  • 实现 catch 块,您可以在其中识别服务器事务错误并实现错误处理逻辑。

以下代码演示如何使用 Core 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 的完全可运行的示例,请参阅使用 Core API用法示例。

便捷事务 API 提供以下实施事务的方法:

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

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

这些方法返回 callback 返回的值。例如,如果您传递给 withTransaction() 方法的 callback 返回文档 { hello: "world" },则 withTransaction() 方法也会返回该文档。

使用便捷事务 API 时,您可以将回调的返回值作为 withTransaction()withSession() 方法的返回值传播,以便在代码中的其他位置使用它们。

使用该 API 时,必须执行以下步骤:

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

  • 为会话中的每个操作执行异步 await 事务语法。

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

以下代码演示如何使用 Convenient Transaction 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 集成了针对这些错误类型的重试逻辑,因此该驱动程序会重试此事务,直到成功提交。

← 聚合(Aggregation)