📜 ⬆️ ⬇️

Transactions in MongoDB

image MongoDB is a great database that is becoming more popular lately. More and more people with SQL experience are starting to use it, and one of the first questions they have is: MongoDB transactions? .

If you believe the answers with stackoverflow, then everything is bad.

MongoDB doesn't support complex multi-document transactions. If that is something you absolutely need it probably isn't a great fit for you. 
 If transactions are required, perhaps NoSQL is not for you. Time to go back to ACID relational databases. 
 MongoDB does a lot of things well, but transactions is not one of those things. 
But we will not believe and implement transactions (ACID * ) based on the MVCC. Below is a story about how these transactions work, and for those who can't wait to see the code, welcome to GitHub (carefully, java).
')
The post is not about MongoDB, but about how to use compare-and-set to create transactions, and durability is provided exactly to the extent that it is provided by the repository.

Data model


Unlike many other NoSQL solutions, MongoDB supports compare-and-set. CAS support allows you to add ACID transactions. If you use any other NoSQL repository with CAS support (for example, HBase, Project Voldemort or ZooKeeper), then the described approach can be applied there.
What is CAS?
  ,      ,          .    -   ,     ,      . 

Actually all the objects that we want to change in the transaction must be protected by CAS, this affects the data model. Suppose we simulate the work of the bank, below is a model of the account both with protection and without it, I hope from this it is clear how to change the rest.
DefenselessDefendants
Model
 { _id : ObjectId(".."), name : "gov", balance : 600 } 
 { _id : ObjectId(".."), version : 0, value : { name : "gov", balance : 600 } } 
Data change
 db.accounts.update( { _id:ObjectId("...") }, { name:"gov", balance:550 } ); 
 db.accounts.update({ _id: ObjectId("..."), version: 0 },{ version : 1, value : { name:"gov", balance:550 } }); 

Further, I will not focus on the fact that an object has a version, and that any change to an object takes place according to its version, but it must be remembered and understood that any change to an object may fail with an error due to competitive access.

In fact, adding a version is not all the changes that need to be made on the model so that it supports transactions, the completely modified model looks like this:

 { _id : ObjectId(".."), version : 0, value : { name : "gov", balance : 600 }, updated : null, tx : null } 

Added fields - updated and tx. This is the service data that is used in the transaction process. The updated structure coincides with the value, meaning it is a modified version of the object that will become value if the transaction passes; tx is an object of the class ObjectId - a foreign key for the _id of the object representing the transaction. The object representing the transaction is also protected by CAS.

Algorithm


It is easy to explain the algorithm, to explain it in such a way that its correctness was obvious, more difficult; therefore, it is necessary that I will operate with some entities before I define them.

Below are the correct statements, the definitions and properties of which the algorithm will be composed later.


States

The pure state describes the object after a successful transaction: value contains data, and upated and tx - null.

A dirty, unfixed state describes an object at the time of a transaction, an updated version contains a new version, and tx is an _id object representing a transaction, this object exists.

The dirty local state describes an object after a successful transaction, but which fell before it could clean up, updated contains a new version, tx is the _id of the object representing the transaction, but the object itself has already been deleted.

Transaction

  1. We read the objects that are involved in the transaction
  2. Create an object representing a transaction (tx)
  3. We write to updated of each object a new value, and in tx - tx._id
  4. Remove tx object
  5. We write the value from updated in the value of each object, and tx and updated are reset.

Reading

  1. We read object
  2. If it is clean, return it.
  3. If dirty zakomichchenny - we write value from updated in value, and tx and updated are nullified
  4. If dirty unaccustomed - change the version of tx, reset updated and tx
  5. Moving on to step # 1


For those who are no longer correct, homework is to check that all the properties and statements are executed, and then using them to prove ACID

Conclusion


We added transactions to MongoDB. But in reality this is not a panacea and they have limitations, some are listed below and some in the comments.
.

FAQ


How can such transactions help with sharding and disabled logging?


In the event of a server error, we can actually get a non-consistent state of the base, but are protected from a non-consistent state caused by a client crash at the time of recording. If the risk of the second is greater than the first, then using transactions we still increase the reliability of the system.

I use Mongu in configuration from one node, will the transactions help me?


Yes, if you use logging, you get honest ACID transactions. If you do not use it, then you already agree on the potential loss of data, since you are not using it and the second way to increase reliability is replication. And if you agree, then transactions in the normal mode preserve consistency with competitive access and client errors, but if the server falls, there is a chance to lose it. But this is not so bad, because when the only node is dropped, the system will be unavailable, so you can make the recovery procedure worse and restore consistency before restarting the node.

Why not use two-phase transactions from official documentation ?


Because they do not work with more than one client. More precisely work but with wild restrictions:

Otherwise, consistency and availability are lost (frozen transactions are possible - the only reasonable step is the refusal to read / write objects that participate in these transactions).

Source: https://habr.com/ru/post/153321/


All Articles