使用核心 API
您可以使用事务来执行一系列操作,直到整个事务提交才更改任何数据。此使用示例使用 核心 API 执行事务。
提示
另请参阅
有关 Node.js 驱动程序中执行事务的更多信息,请参阅事务 指南。
Node.js 驱动还提供了一个方便的事务 API 来执行事务。要了解更多关于方便事务 API 的信息,请参阅使用方便事务 API的使用示例。
示例
考虑一个客户从您的在线商店购买商品的情况。为了记录购买,您的应用程序必须更新您的库存和客户的订单。您的应用程序还需要保存订单详情。
以下表格描述了存储购买数据的集合以及购买如何更改每个集合中的数据。
集合 | 操作 | 更改描述 |
---|---|---|
orders | insert | 插入描述订单的文档 |
customers | update or upsert | 将订单文档中的 _id 追加到客户文档中的订单历史 |
inventory | update | 更新购买后可用物品的数量 |
示例数据
以下代码示例使用 testdb
数据库中的以下示例数据
customers
集合中的文档描述客户及其过去的订单inventory
集合中的文档包括所有物品的数量和描述
以下文档位于 customers
集合中
{ _id: 98765, orders: [] }
inventory
集合包含以下文档
{ item: "sunblock", item_id: 5432, qty: 85 }, { item: "beach towel", item_id: 7865, qty: 41 }
您将购买记录存储在 testdb
数据库的 orders
集合中。此集合为空,因为没有进行任何购买。
以下代码示例使用 cart
和 payment
变量来表示购买物品的示例列表和订单支付详情。以下代码描述了 cart
和 payment
变量的内容
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 };
实现
本节中的代码示例展示了如何使用核心API在会话中执行多文档事务。在此示例中,事务在客户从您的商店购买商品时进行必要的更改。
此示例代码通过以下操作执行事务
调用
startSession()
方法创建新会话调用
startTransaction()
方法并传递一个选项参数来创建新事务在事务中执行以下操作
将包含购买和客户信息的文档插入到
orders
集合中如果有足够的库存来满足购买,则更新
inventory
集合结束事务,如果订单中的任何商品库存不足,则抛出异常
将订单ID添加到客户的过去订单列表中
返回确认事务成功提交的消息以及购买记录的副本
如果所有操作都成功完成,则调用
commitTransaction()
方法提交事务实现一个包含错误处理逻辑的
catch
块调用
abortTransaction()
方法结束事务调用
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(); } }
事务结果
本节描述了事务创建的数据更改。
customers
集合包含带有附加到订单字段的订单 _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 文档
要了解更多关于此用法示例中讨论的任何方法或类型,请参阅以下 API 文档