Monologies of MongoDB 4.0 Detailed explanation of ACID transaction support
(This article was created in collaboration with MongoDB. Thank you for your support for the partners who made SitePoint possible.)
MongoDB 4.0 adds support for multi-document ACID transactions. But does this mean that MongoDB did not support transactions before? Not so, MongoDB has always supported single document transactions. MongoDB 4.0 guarantees that these transactions can be extended to multiple documents, multiple statements, multiple collections, and multiple databases. Without some form of transaction data integrity guarantee, what else is the database useful?
Before diving into this article, you can find all the code here and try multi-documented ACID transactions.
Key Points
Quick Start
Step 1: Start MongoDB
Start a single-node MongoDB ReplicaSet with at least version 4.0.0 on port 27017 of localhost.If you use Docker:
start-mongo.sh
stop-mongo.sh
connect-mongo.sh
mkdir /tmp/data && mongod --dbpath /tmp/data --replSet rs
mongo --eval 'rs.initiate()'
Step 2: Start Java
This demo contains two main programs: and ChangeStreams.java
. Transactions.java
If you use Docker:
First shell:
./compile-docker.sh ./change-streams-docker.sh
./transactions-docker.sh
): pom.xml
./compile-docker.sh ./change-streams-docker.sh
Second shell:
./transactions-docker.sh
Let's compare existing single document transactions with ACID-compatible multi-document transactions for MongoDB 4.0 and learn how to use Java to take advantage of this new feature.
Versions before MongoDB 4.0
Even in MongoDB 3.6 and earlier, each write operation is represented as a transaction scoped at the storage layer with a single document level. Because the document model combines the relevant data, otherwise modeling across different parent-child tables in the tabular schema, MongoDB's atomic single document operation provides transactional semantics that meet the data integrity needs of most applications.
Each typical write operation that modifies multiple documents will actually occur in several independent transactions: one transaction per document.
Let's take a very simple inventory management application as an example.
First of all, I need a MongoDB Replica Set, so please start MongoDB as described above.
Now let's insert the following document into the product collection:
./compile.sh ./change-streams.sh
Assuming a promotion is underway, we want to offer our customers a 20% discount on all products.
But before applying this discount, we want to use Change Streams to monitor how long these operations occur in MongoDB.
Do the following in Mongo Shell:
./transactions.sh
Leave this shell aside, open another Mongo Shell and apply the discount:
MongoDB Enterprise rs:PRIMARY> db.product.insertMany([ { "_id" : "beer", "price" : NumberDecimal("3.75"), "stock" : NumberInt(5) }, { "_id" : "wine", "price" : NumberDecimal("7.5"), "stock" : NumberInt(3) } ])
As you can see, both documents are updated using a single command line, but not in one transaction. Here’s what we saw in the Change Stream shell:
cursor = db.product.watch([{$match: {operationType: "update"}}]); while (!cursor.isExhausted()) { if (cursor.hasNext()) { print(tojson(cursor.next())); } }
As you can see, the cluster time of the two operations (see clusterTime
key) is different: these operations occur within the same second, but the counter for the timestamp is incremented by 1.
So here, update one at a time, even if this happens very quickly, others may read the document while the update runs and only see one of the products has discounts.
Most of the time, this is something you can tolerate in a MongoDB database, as we try to embed closely related or related data into the same document as possible. Therefore, two updates to the same document occur in one transaction:
PRIMARY> db.product.updateMany({}, {$mul: {price:0.8}}) { "acknowledged" : true, "matchedCount" : 2, "modifiedCount" : 2 } PRIMARY> db.product.find().pretty() { "_id" : "beer", "price" : NumberDecimal("3.00000000000000000"), "stock" : 5 } { "_id" : "wine", "price" : NumberDecimal("6.0000000000000000"), "stock" : 3 }
However, sometimes you can't model all the relevant data into a single document, and there are many reasons to choose not to embed the document.
MongoDB 4.0 using multi-document ACID transactions
Multi-documented ACID transactions in MongoDB are very similar to what you might have learned from traditional relational databases.
MongoDB transactions are related conversational operations that must be submitted atomically or completely rolled back in an all-or-nothing execution manner.
Transactions are used to ensure that operations are atomic even across multiple collections or databases. Therefore, using snapshot isolation reads, another user can only see all actions or no actions.
Let's now add a shopping cart to our example.
In this example, 2 collections are needed because we are dealing with 2 different business entities: inventory management and carts that each client can create during shopping. Each document in these collections has a different life cycle.
The documentation in the product collection indicates the item I am selling. This includes the current price of the product and the current inventory. I created a POJO to represent it: Product.java
.
./compile-docker.sh ./change-streams-docker.sh
When the client adds its first item to the cart, the cart is created, and when the client continues to checkout or leaves the website, the cart is deleted. I created a POJO to represent it: Cart.java
.
./transactions-docker.sh
The challenge here is that I can’t sell more than I have: If I have 5 beers to sell, I can’t have more than 5 beers in the shopping carts on different clients.
To ensure this, I have to make sure that the operation of creating or updating the client cart is atomic with the inventory update. This is where multi-document transactions come into play. If someone tries to buy something I don't have in stock, the transaction must fail. I will add a constraint to the product inventory:
./compile.sh ./change-streams.sh
(Note that this is already included in the Java code.)
To monitor our examples, we will use MongoDB Change Streams introduced in MongoDB 3.6.
In each thread of this process called ChangeStreams.java
, I will monitor one of the 2 collections and print each operation and its associated cluster time.
...(The following content needs to be supplemented with Java code snippets and explanations based on the provided code. The length is too long and omitted here)....
Next steps
Thanks for taking the time to read my post – I hope you find it useful and interesting. As a reminder, all code can be found in this Github repository for you to experiment with.
If you are looking for a very simple way to get started, you can do it in just 5 clicks in the MongoDB Atlas database service in the cloud.
In addition, multi-document ACID transactions are not the only new feature in MongoDB 4.0, so feel free to check out our free course M040: New Features and Tools in MongoDB 4.0 at MongoDB University and our guide on new features in MongoDB 4.0 , where you can learn more about native type conversions, new visualization and analysis tools, and Kubernetes integration.
...(The following content is FAQ, the article is too long, omitted here)....
The above is the detailed content of Java and MongoDB 4.0 Support for Multi-document ACID Transactions. For more information, please follow other related articles on the PHP Chinese website!