Transaction Management in MongoDB
As I am using MongoDB since last 3 years in many environment and for many applications which is ranging from small application to enterprise application. This is my one of favourite database due to it's NOSQL nature, it's performance and simplicity in writing query.
Mainly since all my experiences I faced two main problems with MongoDB
1) Design an schema for application -
This is challenge for me because as my basic learning and mostly I developed application using RDBMS. So in nutshell my mind drive me to correlate each schema design like RDBMS, primary key, foreign key & Joins. Which is really create mess. So now before design schema I always create picture like I have to create only one document for all forms and then I start decouple it. I am trying many permutation & combination of possibilities to finalise my design which I will cover into next article.
2) Transaction Management
Simple principle of transaction management is "do-all-or-nothing".
Before the MongoDB 4.0, It's too much difficult and clumsy way to manage transactions because no inbuilt support provided for commit or rollback. MongoDB 4.0 released feature of Transaction Management to just save developers from this overhead.
MongoDB 4.0 adds support for multi-document ACID transactions, making it the only open source database to combine the speed, flexibility, and power of the document model with ACID guarantees. Through snapshot isolation, transactions provide a consistent view of data, and enforce all-or-nothing execution to maintain data integrity. Starting in version 4.0, MongoDB provides the ability to perform multi-document transactions against replica sets. With multi-document transactions, until a transaction commits, no write operations in the transaction are visible outside the transaction. That is, the multi-document transactions are atomic.
Feature Compatibility
MongoDB 4.0 or greater
Transactions & MongoDB Drivers
Clients require MongoDB drivers updated for MongoDB 4.0.
- Java 3.8.0
- Python 3.7.0
- C 1.11.0
- C# 2.7
- Node 3.1.0
- Ruby 2.6.0
- Perl 2.0.0
- PHPC 1.5.0
- Scala 2.4.0
How to use that?
I am just showing here which will help you to implement this in 3 different technologies.
1) Shell Method
session = db.getMongo().startSession();//start session
session.startTransaction();//start session
//transaction1
session.getDatabase("test").student.insert({"name" : "Pankaj saboo"});
//transaction2
session.getDatabase("test").student.insert({"name" : "Neeraj Vishwakarma"});
After running above block if you check "student" collection of "test" database you will not find the record.
To commit above initiated transaction use following statement
session.commitTransaction()
To Rollback above initiated transactions use following statement
session.abortTransaction()
The pending uncommitted changes are only visible inside the session context (the session which has started the transaction) and are not visible outside. )
2) In Java
try {
ClientSession clientSession = client.startSession();
clientSession.startTransaction();
collection.insertOne(clientSession, docOne);
collection.insertOne(clientSession, docTwo);
clientSession.commitTransaction();
} catch(Exception e){
//Abort / Rollback transaction
clientSession.abortTransaction();
}
3) In NodeJS
const { MongoClient } = require('mongodb');
const uri = 'mongodb://localhost:27017,localhost:27018,localhost:27019/test';
const client = await MongoClient.connect(uri, { useNewUrlParser: true, replicaSet: 'rs' });
const db = client.db();
async function transaction(from, to, amount) {
const session = client.startSession();
session.startTransaction({
readConcern: { level: 'snapshot' },
writeConcern: { w: 'majority' }
});
try {
const test1Collection = client.db('test1').collection('employees');
const test2Collection = client.db('test2').collection('events');
//transaction 1
await test1Collection.updateOne({ employee: 3 },{ $set: { status: 'Inactive' } },
{ session });
//transaction 2
await test2Collection.insertOne({employee: 3,status: { new: 'Inactive', old: 'Active' }
},{ session });
await session.commitTransaction();
session.endSession();
} catch (error) {
// If an error occurred, abort the whole transaction and// undo any changes that might have happenedawait session.abortTransaction();await session.abortTransaction();
session.endSession();
throw error; // Rethrow so calling function sees error
}
}
If while performing multiple actions if transaction conflict occurs MongoDB catches the conflict and return the error on the insert (even before the commit).
Software Engineer, Backend Engineer
4 年thank you for this.
Back End Developer
4 年I've recently used transactions in my projects and find it awesome
Research Assistant @ Statistical Machine Learning Lab
4 年Thanks for this useful article.
Senior Software Engineer at Intuit
5 年Really helpful article! Would you please elaborate me how transaction were managed before mongodb4.0
Frontend Developer | Angular | Typescript
5 年Gosh would have been nice if commitTransaction could be commitTransaction({ closeSession: true }) but its a small price to pay