Core API 사용
트랜잭션을 수행하여 전체 트랜잭션이 커밋될 때까지 데이터를 변경하지 않는 일련의 작업을 실행할 수 있습니다. 이 사용 예제에서는 Core API 를 사용하여 트랜잭션을 수행합니다.
팁
다음도 참조하세요.
Node.js 운전자 에서 트랜잭션을 수행하는 방법에 학습 보려면 트랜잭션 가이드 를 참조하세요.
Node.js 드라이버는 트랜잭션을 수행할 수 있도록 편리한 트랜잭션 API도 제공합니다. 편리한 트랜잭션 API에 대해 자세히 알아보려면 편리한 트랜잭션 API 사용 예제를 참조하세요.
예시
고객이 온라인 상점에서 품목을 구매하는 상황을 가정해 보겠습니다. 구매를 기록하려면 애플리케이션에서 재고와 고객 주문을 업데이트해야 합니다. 애플리케이션은 주문 세부 정보도 저장해야 합니다.
다음 표에서는 구매 데이터를 저장하는 collection과 구매가 각 collection의 데이터를 변경하는 방법에 대해 설명합니다.
컬렉션 | 작업 | 변경 사항 설명 |
---|---|---|
| insert | 주문을 설명하는 문서를 삽입합니다 |
| 업데이트 또는 업서트 | 주문 문서의 |
| update | 구매 후 사용 가능한 품목의 수량 업데이트 |
샘플 데이터
이 코드 예시에서는 testdb
데이터베이스의 다음 샘플 데이터를 사용합니다.
customers
컬렉션에서 고객과 과거 주문을 설명하는 문서모든 항목의 수량 및 설명이 포함된
inventory
collection의 문서
다음 문서가 customers
collection에 있습니다.
{ _id: 98765, orders: [] }
inventory
컬렉션에는 다음 문서가 포함되어 있습니다.
{ item: "sunblock", item_id: 5432, qty: 85 }, { item: "beach towel", item_id: 7865, qty: 41 }
데이터베이스의 collection 컬렉션에 구매 기록을 저장합니다.orders
testdb
이 collection은 구매가 없으므로 비어 있습니다.
코드 예제에서는 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 };
구현
이 섹션의 코드 예제는 Core API를 사용하여 세션에서 다중 문서 트랜잭션을 수행하는 방법을 보여줍니다. 이 예제에서는 트랜잭션이 고객이 매장에서 품목을 구매할 때 필요한 변경을 수행합니다.
이 예시 코드는 다음 조치를 통해 트랜잭션을 수행합니다.
startSession()
메서드를 호출하여 새 세션을 만듭니다.옵션 매개변수와 함께
startTransaction()
메서드를 호출하여 새 트랜잭션을 생성합니다.트랜잭션 내에서 다음 작업을 수행합니다.
구매 및 고객에 대한 정보가 포함된
orders
collection에 문서를 삽입합니다.구매를 처리하기에 충분한 재고가 있는 경우
inventory
collection을 업데이트합니다.주문에 포함된 품목에 대한 재고가 충분하지 않은 경우 트랜잭션을 종료하고 예외를 발생시킵니다.
고객의 과거 주문 목록에 주문 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
collection에는 주문 필드에 주문 _id
이 추가된 고객 문서가 포함되어 있습니다.
{ "_id": 98765, "orders": [ "61dc..." ] }
inventory
collection에는 "sunblock"
및 "beach towel"
항목에 대한 업데이트된 수량이 포함되어 있습니다.
[ { "_id": ..., "item": "sunblock", "item_id": 5432, "qty": 84 }, { "_id": ..., "item": "beach towel", "item_id": 7865, "qty": 39 } ]
orders
collection에는 주문 및 결제 정보가 포함되어 있습니다.
[ { "_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 설명서를 참조하세요.