Make the MongoDB docs better! We value your opinion. Share your feedback for a chance to win $100.
MongoDB Branding Shape
Click here >
Docs 菜单

使用 Core API

您可以执行一个事务来运行一系列操作,这些操作在提交整个事务之前不会更改任何数据。 此用法示例使用Core API执行事务。

提示

要了解有关在 Node.js 驱动程序中执行事务的更多信息,请参阅事务指南。

Node.js 驱动程序还提供了便捷事务 API 来执行事务。 要了解有关便捷事务 API 的更多信息,请参阅使用便捷事务 API用法示例。

考虑客户从您的在线商店购买商品的情况。 要记录购买,应用程序必须更新库存和客户订单。 您的应用程序还需要保存订单详细信息。

下表描述了存储购买数据的collection,以及购买如何更改每个collection中的数据。

Collection
操作
变更说明

orders

insert

插入描述订单的文档

customers

更新或更新插入

将订单文档中的_id附加到客户文档中的订单历史记录中

inventory

update

更新购买后可用商品的数量

代码示例使用testdb数据库中的以下样本数据:

  • customers 集合中描述客户及其过往订单的文档

  • inventorycollection中的文档,其中包括所有商品的数量和说明

以下文档位于customerscollection中:

{ _id: 98765, orders: [] }

inventory 集合包含以下文档:

{ item: "sunblock", item_id: 5432, qty: 85 },
{ item: "beach towel", item_id: 7865, qty: 41 }

您将购买记录存储在testdb数据库的orders集合中。 此collection为空,因为没有任何购买操作。

代码示例使用cartpayment变量来表示所购商品的样本清单和订单付款详情。 以下代码描述了cartpayment变量的内容:

const cart = [
{ item: 'sunblock', item_id: 5432, qty: 1, price: 5.19 },
{ item: 'beach towel', item_id: 7865, qty: 2, price: 15.99 }
];
const payment = { customer: 98765, total: 37.17 };

本节中的代码示例演示了如何使用 Core API 在会话中执行多文档事务。 在此示例中,事务在客户从您的商店购买商品时进行所需的更改。

此示例代码通过以下动作执行事务:

  1. 调用startSession()方法创建新会话

  2. 使用选项参数调用startTransaction()方法以创建新事务

  3. 在事务中执行以下操作:

    • 将文档插入到orders集合中,其中包含有关购买和客户的信息

    • 如果有足够的库存来完成采购,更新inventorycollection

    • 如果订单中的任何商品没有足够的库存,则结束事务并引发异常

    • 将订单 ID 添加到客户过去的订单列表中

    • 返回一条消息,确认已使用购买记录的副本成功提交事务

  4. 如果所有操作均成功完成,则调用commitTransaction()方法提交事务

  5. 实现包含错误处理逻辑的catch区块

  6. 调用abortTransaction()方法结束事务

  7. 调用endSession()方法结束会话

async function placeOrder(client, cart, payment) {
const transactionOptions = {
readConcern: { level: 'snapshot' },
writeConcern: { w: 'majority' },
readPreference: 'primary'
};
// Start the session
const session = client.startSession();
try {
// Start the transaction in the session, specifying the transaction options
session.startTransaction(transactionOptions);
const ordersCollection = client.db('testdb').collection('orders');
/* Within the session, insert an order that contains information about the
customer, items purchased, and the total payment */
const orderResult = await ordersCollection.insertOne(
{
customer: payment.customer,
items: cart,
total: payment.total,
},
{ session }
);
const inventoryCollection = client.db('testdb').collection('inventory');
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. */
const inStock = await inventoryCollection.findOneAndUpdate(
{
item_id: item.item_id,
item_id: { $gte: item.qty }
},
{ $inc: { 'qty': -item.qty }},
{ session }
)
if (inStock === null) {
throw new Error('Insufficient quantity or item ID not found.');
}
}
const customerCollection = client.db('testdb').collection('customers');
// Within the session, add the order details to the "orders" array of the customer document
await customerCollection.updateOne(
{ _id: payment.customer },
{ $push: { orders: orderResult.insertedId }},
{ session }
);
// Commit the transaction to apply all updates performed within it
await session.commitTransaction();
console.log('Transaction successfully committed.');
} catch (error) {
/*
Handle any exceptions thrown during the transaction and end the
transaction. Roll back all the updates performed in the transaction.
*/
if (error instanceof MongoError && error.hasErrorLabel('UnknownTransactionCommitResult')) {
// Add your logic to retry or handle the error
}
else if (error instanceof MongoError && error.hasErrorLabel('TransientTransactionError')) {
// Add your logic to retry or handle the error
} else {
console.log('An error occured in the transaction, performing a data rollback:' + error);
}
await session.abortTransaction();
} finally {
// End the session
await session.endSession();
}
}

提示

显式资源管理

Node.js驱动程序本身支持对 MongoClientClientSessionChangeStreams 和游标进行显式资源管理。此功能为实验性功能,可能会发生更改。要学习;了解如何使用显式资源管理,请参阅v6.9发布说明。

本节描述事务创建的数据更改。

The customers collection 包含客户文档,其订单字段附加了订单_id

{
"_id": 98765,
"orders": [
"61dc..."
]
}

inventory集合包含"sunblock""beach towel"项的更新数量:

[
{
"_id": ...,
"item": "sunblock",
"item_id": 5432,
"qty": 84
},
{
"_id": ...,
"item": "beach towel",
"item_id": 7865,
"qty": 39
}
]

orders集合包含订单和付款信息:

[
{
"_id": "...",
"customer": 98765,
"items": [
{
"item": "sunblock",
"item_id": 5432,
"qty": 1,
"price": 5.19
},
{
"item": "beach towel",
"item_id": 7865,
"qty": 2,
"price": 15.99
}
],
"total": 37.17
}
]

要了解有关此用法示例中讨论的任何方法或类型的更多信息,请参阅以下 API 文档: