Transactions in MongoDB

Sanya Davtyan - Sep 4 - - Dev Community

Transactions in MongoDB allow you to execute multiple operations as a single unit of work, ensuring that either all operations succeed or none of them do. This is useful for maintaining data consistency, especially in scenarios where multiple related operations must all succeed or fail together. Here's a quick overview:

Single Document Transactions
MongoDB supports atomic operations at the single document level, meaning any write operation to a single document (like an update or insert) is atomic. However, for more complex scenarios involving multiple documents or collections, you need multi-document transactions.

Multi-Document Transactions
Introduced in MongoDB 4.0, multi-document transactions are used for operations spanning multiple documents or collections. Here's how you can use them:

Start a Transaction: You begin a transaction by starting a session and then starting a transaction within that session.

Perform Operations: Execute your read and write operations within the context of the transaction.

Commit or Abort: After performing the desired operations, you can either commit the transaction to apply all changes or abort it to revert all changes.

Database lock
In MongoDB, transactions typically do not block the entire database unless explicitly configured to do so under certain circumstances. MongoDB supports multi-document transactions on replica sets starting from version 4.0, and on sharded clusters starting from version 4.2.

Concurrency: Transactions in MongoDB are designed to operate concurrently with other operations. Transactions do not block read or write operations on other documents or collections within the same database unless a specific document-level or collection-level lock is acquired.

Isolation: MongoDB transactions provide snapshot isolation for read operations, meaning transactions only see consistent data as of the transaction start time. Write operations within a transaction are isolated from other transactions until committed.

Locking: MongoDB uses optimistic concurrency control (OCC) for transactions by default, which helps in minimizing locks and improving performance. Locks are acquired on a per-document basis during write operations, and these locks are released as soon as the transaction commits or rolls back.

Impact: While transactions do acquire locks, they are typically short-lived and should not block the entire database. However, long-running transactions or excessive contention on the same documents could potentially impact overall database performance.

Configuration: MongoDB allows some flexibility in transaction behavior through configuration parameters like commitQuorum, which can affect how transactions commit across replica sets.

In summary, MongoDB transactions are designed to be non-blocking for the entire database under normal circumstances. They provide isolation and atomicity for multi-document operations while allowing concurrent read and write operations to other parts of the database.

Basic Example in Node js

`const session = db.getMongo().startSession();

  session.startTransaction();

try {
  // Perform operations within the transaction
  const ordersCollection = session.getDatabase("mydb").orders;
  ordersCollection.insertOne({ _id: 1, item: "A", qty: 10 });

  const inventoryCollection = 
  session.getDatabase("mydb").inventory;
  inventoryCollection.updateOne({ item: "A" }, { $inc: { qty: -10 } });

  session.commitTransaction();
} catch (error) {
  session.abortTransaction();
  throw error;
} finally {
  session.endSession();
}`
Enter fullscreen mode Exit fullscreen mode

Key Points

  • ACID Compliance: Transactions in MongoDB provide ACID (Atomicity, Consistency, Isolation, Durability) guarantees for multi-document operations.

  • Session: Transactions are associated with a session, which you need to explicitly manage.

  • Performance Considerations: Transactions can impact performance, so use them judiciously and avoid long-running transactions.

Transaction Options

  1. Read Concern The readConcern option controls the level of isolation for read operations in a transaction. It determines how much consistency is guaranteed when you read data during a transaction.
  • local: Reads the most recent data available on the node (this might not be acknowledged by the majority of nodes in a replica set).

  • majority: Reads only data that has been acknowledged by a majority of the replica set members. This ensures that the data is durable across most nodes.

  • snapshot: Ensures that all reads within the transaction see a snapshot of the data as it was at the start of the transaction. This provides strong isolation for reads during the transaction.

session.startTransaction({ readConcern: { level: "snapshot" } });

Enter fullscreen mode Exit fullscreen mode

2. Write Concern
The writeConcern option determines how much guarantee MongoDB provides when confirming writes during a transaction. It controls how many replica set members must acknowledge the write before the transaction is considered successful.

  • w: 1: Requires only the primary node to acknowledge the write.

  • w: majority: Requires acknowledgment from the majority of nodes in a replica set, ensuring that the write is replicated and durable.

You can also configure j: true (journaled) to ensure that the write is flushed to the disk before acknowledging success.

session.startTransaction({ writeConcern: { w: "majority", j: true } });

Enter fullscreen mode Exit fullscreen mode

3. Max Commit Time
The maxCommitTimeMS option allows you to set a time limit for how long the commit operation should take. If the commit operation exceeds this time, it will fail.

This is useful when you want to control the maximum latency of your transactions in distributed environments.

session.startTransaction({ maxCommitTimeMS: 1000 });

Enter fullscreen mode Exit fullscreen mode

4. Transaction Timeout
While MongoDB doesn't allow you to set an explicit timeout for the entire transaction, you can use logic in your application to abort a transaction if it takes too long. This is important because long-running transactions can hold locks on resources and degrade performance.

5. Read-Write Conflict Detection
MongoDB automatically handles conflicts between read and write operations within a transaction. If two transactions try to modify the same document, MongoDB will abort one of the transactions to avoid data inconsistency.

Understanding Transactions in Databases:
A Simple Banking Example

In the world of databases, transactions are fundamental to ensuring that multiple operations are executed in a consistent and reliable manner. Let’s explore this concept through a simple banking example to illustrate the importance of transaction management.

_Scenario: Bank Account Transfers
_Imagine you have three values representing different bank accounts:

Account A: $10
Account C: $100
Now, consider a transaction where:

Account A needs to deduct $15 from its balance.
Account C needs to deduct $15 from its balance and transfer it to Account A.
To maintain data consistency, we must ensure that:

The deduction from Account C is completed before the deduction from Account A.
Account A should not have a negative balance during the transaction.
Transaction Process
Here’s how you might manage this transaction:

Start Transaction: Begin a transaction to ensure all operations are performed as a single unit of work.

Perform Operations:

Deduct $15 from Account C: This decreases Account C’s balance from $100 to $85.
Add $15 to Account A: This increases Account A’s balance from $10 to $25.
Commit Transaction: If both operations are successful, commit the transaction to save the changes.

Handle Errors: If any part of the transaction fails (e.g., insufficient funds in Account C), rollback the transaction to revert all changes. This ensures that Account A doesn’t end up with an incorrect balance due to partial updates.

Example Implementation in Node js

const session = db.getMongo().startSession();

session.startTransaction({
  readConcern: { level: "majority" },
  writeConcern: { w: "majority", j: true },
  maxCommitTimeMS: 2000
});

try {
  const accounts = session.getDatabase("bank").accounts;

  // Deduct from Account C
  accounts.updateOne({ _id: "C" }, { $inc: { balance: -15 } });

  // Add to Account A
  accounts.updateOne({ _id: "A" }, { $inc: { balance: 15 } });

  // Commit the transaction
  session.commitTransaction();
} catch (error) {
  session.abortTransaction();
  console.error("Transaction failed:", error);
} finally {
  session.endSession();
}

Enter fullscreen mode Exit fullscreen mode

Importance of Order and Consistency
In scenarios such as banking or eCommerce:

Order Matters: The sequence of operations is crucial. If Account A deducted from before Account C, it could lead to inconsistencies or overdraft penalties.
Consistency: Transactions ensure that all operations within a transaction are completed successfully before applying any changes. If something goes wrong, the transaction is rolled back, maintaining data integrity.

Conclusion
Transactions play a critical role in maintaining data consistency and integrity in databases. They ensure that operations are executed in a predictable order, and any failure in one part of the transaction can be handled gracefully by rolling back changes. This is especially important in scenarios where the order of operations affects the outcome, such as financial transactions or inventory management.

. .
Terabox Video Player