MongoDB transactions allow you to execute multiple operations as a single, atomic unit. This means either all operations within the transaction succeed and are applied to the database, or if any operation fails, all changes are rolled back. This guide will walk you through the process using the mongosh shell.
Prerequisites
Before you begin, ensure you have:
- A running MongoDB instance (version 4.0 or higher, as transactions were introduced in 4.0).
- mongosh (MongoDB Shell) installed and connected to your MongoDB instance.
- A sample database and collection. For this guide, we'll assume a database named a_test and a collection named student.
// Switch to the database
use a_test;
// Insert a sample document if it doesn't exist
db.student.insertOne({ _id: "s1", name: "Alice", age: 10, grade: "A" });
// Verify the initial data
db.student.findOne({ _id: "s1" });
Step-by-Step Transaction Example
Follow these steps to perform a transaction:
1. Create a MongoDB Session
Transactions in MongoDB are associated with a session. First, you need to create one.
Step-by-Step Transaction Example
Follow these steps to perform a transaction:
1. Create a MongoDB Session
Transactions in MongoDB are associated with a session. First, you need to create one.
// Create a new client session
session = db.getMongo().startSession();
2. Start the Transaction
Once the session is created, you can initiate a transaction on it. It's good practice to define readConcern and writeConcern for the transaction to ensure data consistency and durability.
2. Start the Transaction
Once the session is created, you can initiate a transaction on it. It's good practice to define readConcern and writeConcern for the transaction to ensure data consistency and durability.
- readConcern: { "level": "snapshot" }: Ensures that reads within the transaction see a consistent snapshot of the data, preventing dirty reads and non-repeatable reads.
- writeConcern: { "w": "majority" }: Ensures that write operations are acknowledged by the majority of the replica set members, providing strong durability guarantees.
session.startTransaction({
"readConcern": { "level": "snapshot" },
"writeConcern": { "w": "majority" }
});
3. Get the Collection within the Session
All operations within the transaction must be performed on collections obtained through the session object.
3. Get the Collection within the Session
All operations within the transaction must be performed on collections obtained through the session object.
// Get the 'student' collection from the 'a_test' database within the session
coll = session.getDatabase('a_test').getCollection('student');
4. Check Data (Pre-Update)
You can perform read operations within the transaction. This read will reflect the state of the data before any modifications made within the current transaction, but it will see the latest committed data from outside the transaction.
coll = session.getDatabase('a_test').getCollection('student');
4. Check Data (Pre-Update)
You can perform read operations within the transaction. This read will reflect the state of the data before any modifications made within the current transaction, but it will see the latest committed data from outside the transaction.
// Find the document with _id "s1"
coll.findOne({ _id: "s1" });
// Expected output (assuming initial state): { _id: "s1", name: "Alice", age: 10, grade: "A" }
5. Update Data within the Transaction
Now, perform your write operation. This change is not yet visible to other sessions or outside this transaction. It's only staged within the current transaction's context.
5. Update Data within the Transaction
Now, perform your write operation. This change is not yet visible to other sessions or outside this transaction. It's only staged within the current transaction's context.
// Update the 'age' field for the document with _id "s1"
coll.findOneAndUpdate({ _id: "s1" }, { $set: { age: 11 } });
6. Check Data Again (Within Transaction)
If you check the data again within the same transaction, you will see the updated value. This demonstrates that changes are visible locally within the transaction's scope before being committed globally.
6. Check Data Again (Within Transaction)
If you check the data again within the same transaction, you will see the updated value. This demonstrates that changes are visible locally within the transaction's scope before being committed globally.
// Check the document again within the transaction
coll.findOne({ _id: "s1" });
// Expected output: { _id: "s1", name: "Alice", age: 11, grade: "A" }
7. Global Verification (Before Commit/Abort)
To confirm that the changes are not yet public, open a new mongosh window or session and query the same document. You will see the original age value.
7. Global Verification (Before Commit/Abort)
To confirm that the changes are not yet public, open a new mongosh window or session and query the same document. You will see the original age value.
// In a NEW mongosh window/session:
use a_test;
db.student.findOne({ _id: "s1" });
// Expected output: { _id: "s1", name: "Alice", age: 10, grade: "A" }
Finalizing the Transaction: Abort or Commit
You have two options to finalize the transaction: aborting it (rolling back changes) or committing it (making changes permanent).
Finalizing the Transaction: Abort or Commit
You have two options to finalize the transaction: aborting it (rolling back changes) or committing it (making changes permanent).
Option A: Abort Transaction (Rollback)
If you decide to cancel the changes made within the transaction, you can abort it. All modifications made since startTransaction() will be discarded.
If you decide to cancel the changes made within the transaction, you can abort it. All modifications made since startTransaction() will be discarded.
// Abort the transaction
session.abortTransaction();
print("Transaction aborted. Changes rolled back.");
After aborting, verify the result in the global database. The data will revert to its state before the transaction began.
// Verify the result in the global database (in any mongosh window)
use a_test;
db.student.findOne({ _id: "s1" });
// Expected output: { _id: "s1", name: "Alice", age: 10, grade: "A" }
Option B: Commit Transaction (Apply Changes)
If the operations within the transaction were successful and you want to make the changes permanent and visible to all other sessions, you commit the transaction.
Option B: Commit Transaction (Apply Changes)
If the operations within the transaction were successful and you want to make the changes permanent and visible to all other sessions, you commit the transaction.
// Commit the transaction
session.commitTransaction();
print("Transaction committed. Changes applied to the database.");
After committing, verify the result in the global database. The data will now reflect the changes made within the transaction.
After committing, verify the result in the global database. The data will now reflect the changes made within the transaction.
// Verify the result in the global database (in any mongosh window)
use a_test;
db.student.findOne({ _id: "s1" });
// Expected output: { _id: "s1", name: "Alice", age: 11, grade: "A" }
Important Notes on Transactions
This guide provides a foundational understanding of using transactions in MongoDB with mongosh.
Important Notes on Transactions
- Replica Sets Only: Transactions are only supported on replica sets. They are not available on standalone MongoDB instances.
- Sharded Clusters: Transactions are also supported on sharded clusters starting from MongoDB 4.2.
- Size Limitations: There are limitations on the number of operations and total document size within a single transaction.
- Error Handling: In a real application, you would wrap transaction operations in try-catch blocks to handle potential errors and ensure abortTransaction() is called if an error occurs.
- Session Management: Always ensure you close or end sessions properly in your application code to free up resources. In mongosh, the session is automatically managed when you close the shell or if it's explicitly ended.
This guide provides a foundational understanding of using transactions in MongoDB with mongosh.
ไม่มีความคิดเห็น:
แสดงความคิดเห็น