Docs Home / Node.js Driver / Transactions

Use the Convenient Transaction API使用便捷事务API

You can perform a transaction to run a series of operations that do not change any data until the entire transaction is committed. This usage example uses the Convenient Transaction API to perform a transaction.您可以执行事务以运行一系列操作,这些操作在整个事务提交之前不会更改任何数据。此使用示例使用方便事务API来执行事务。

Tip

To learn more about the performing transactions in the Node.js driver, see the Transactions guide.要了解更多关于在Node.js驱动程序中执行事务的信息,请参阅事务指南

The Node.js driver also provides the Core API to perform transactions. To learn more about the Core API, see the Use the Core API usage example.Node.js驱动程序还提供了核心API来执行事务。要了解有关核心API的更多信息,请参阅使用核心API使用示例。

Example示例

Consider a situation in which a customer purchases items from your shop. To record the purchase, your application must update your inventory and record the order information.考虑一个客户从你的商店购买商品的情况。要记录购买,您的应用程序必须更新您的inventory并记录订单信息。

The following table describes the collections that store purchase data and how a purchase changes the data in each collection.下表描述了存储采购数据的集合以及采购如何更改每个集合中的数据。

Collection集合Operation操作Description of the Change变更说明
ordersinsertInserts a document that describes the order插入描述订单的文档
inventoryupdateUpdates the quantities of items available after a purchase更新购买后可用物品的数量

Sample Data样品数据

The inventory collection contains the following documents:inventory集合包含以下文档:

{ item: "sunblock", qty: 85, price: 6.0 },
{ item: "beach chair", qty: 30, price: 25.0 }

You store purchase records in the orders collection of the testdb database. This collection is empty, as there have been no purchases.您将购买记录存储在testdb数据库的orders集合中。此集合是空的,因为没有购买。

Implementation实施

The code example in this section demonstrates how to use the Convenient Transaction API to perform a multi-document transaction in a session. In this example, the transaction makes the changes needed when a customer purchases items from your shop.本节中的代码示例演示了如何使用方便事务API在会话中执行多文档事务。在这个例子中,当客户从你的商店购买商品时,事务会进行所需的更改。

This example code performs a transaction through the following actions:此示例代码通过以下操作执行事务:

  1. Calls the withSession() method on the client to implicitly create the session and run the callback passed to it within the session.在客户端调用withSession()方法隐式创建会话,并在会话中运行传递给它的回调。
  2. Calls the withTransaction() method on the session to create a transaction, run the callback passed to it, and commit the transaction. If the transaction fails, this method ends the transaction and returns an error message.在会话上调用withTransaction()方法以创建事务,运行传递给它的回调,并提交事务。如果事务失败,此方法将结束事务并返回错误消息。
  3. Performs the following operations within the transaction:在事务中执行以下操作:

    • Updates the inventory and orders collections if there is sufficient inventory to fulfill the purchase如果有足够的库存来完成采购,则更新inventoryorders集合
    • Ends the transaction and throws an exception if there isn't sufficient inventory for any item in the order如果订单中的任何商品没有足够的inventory,则结束事务并抛出异常
    • Returns a message acknowledging that the transaction committed successfully with a copy of the purchase record返回一条消息,确认事务已成功提交,并附上购买记录的副本
  4. Prints the return type of withSession(), which is either the error message or the acknowledgment that the transaction completed.打印withSession()的返回类型,它要么是错误消息,要么是事务完成的确认。
const txnResult = await client.withSession(async (session) =>
session
.withTransaction(async (session) => {
const invColl = client.db("testdb").collection("inventory");
const recColl = client.db("testdb").collection("orders");

let total = 0;
for (const item of order) {
/* Update the inventory for the purchased items. End the transaction if the quantity of an item in the inventory is insufficient to complete the purchase.更新采购物品的inventory。如果inventory中某个项目的数量不足以完成采购,则结束事务。 */
const inStock = await invColl.findOneAndUpdate(
{
item: item.item,
qty: { $gte: item.qty },
},
{ $inc: { qty: -item.qty } },
{ session }
);
if (inStock === null) {
await session.abortTransaction();
return "Item not found or insufficient quantity.";
}
const subTotal = item.qty * inStock.price;
total = total + subTotal;
}

// Create a record of the purchase创建购买记录
const receipt = {
date: new Date(),
items: order,
total: total,
};
await recColl.insertOne(receipt, { session });
return (
"Order successfully completed and recorded!\nReceipt:\n" +
JSON.stringify(receipt, null, 1)
);
}, null)
.finally(async () => await client.close())
);

console.log(txnResult);

Sample Orders and Transaction Results订单和事务结果示例

This section describes the results of the transactions performed for two sample orders.本节描述了对两个示例订单执行的事务结果。

Sufficient inventory exists for the following order, so the transaction successfully completes:以下订单有足够的inventory,因此事务成功完成:

{ item: "sunblock", qty: 3 },
{ item: "beach chair", qty: 1 }

After passing this order to the example transaction code, the code outputs the following result:将此订单传递给示例事务代码后,代码输出以下结果:

Order successfully completed and recorded!
Receipt:
{
"date": "2023-08-25T20:06:52.564Z",
"items": [
{ "item": "sunblock", "qty": 3 },
{ "item": "beach chair", "qty": 1 }
],
"total": 43,
"_id": "..."
}

In the inventory collection, the quantity of "sunblock" is now 82 and the quantity of "beach chair" is 29. The orders collection contains the record of the purchase.inventory集合中,"sunblock"(防晒霜)的数量现在是82"beach chair"(沙滩椅)的数量是29orders集合包含采购记录。

There is not sufficient inventory for the following order, so the driver ends the transaction:以下订单没有足够的inventory,因此司机结束事务:

{ item: "volleyball", qty: 1 }

After passing this order to the example transaction code, the code outputs the following result:将此订单传递给示例事务代码后,代码输出以下结果:

Item not found or insufficient quantity.

Since the driver ends the transaction, there are no changes to the inventory and orders collections.由于驱动程序结束了事务,inventoryorders集合没有变化。

API Documentation文档

To learn more about any of the methods or types discussed in this usage example, see the following API Documentation:要了解有关本使用示例中讨论的任何方法或类型的更多信息,请参阅以下API文档: