Hokkyokusei
Hokkyokusei

Reputation: 1234

Commit and Rollback transactions in MongoDB Java

Currently, I am using the following code:-

(I have marked the two important lines in the code. Between these lines are just some operations on existing documents)

clientSession.startTransaction();  // Important Line 1.
Document walletDetailDoc = new Document("identifier", "walletBalanceDistribution");
Document foundWalletDetailDoc1 = (Document) walletDistributionCollection.find(walletDetailDoc).first();
walletDetailDoc = new Document("identifier", to + "Backup");
Document foundWalletDetailDoc2 = (Document) walletDistributionCollection.find(walletDetailDoc).first();
walletDetailDoc = new Document("identifier", from + "Backup");
Document foundWalletDetailDoc3 = (Document) walletDistributionCollection.find(walletDetailDoc).first();
assert foundWalletDetailDoc1 != null;
assert foundWalletDetailDoc2 != null;
assert foundWalletDetailDoc3 != null;
Bson updateWalletDoc = walletDetailDoc;
Bson updateWalletDocOperation = new Document("$set", updateWalletDoc);
walletDistributionCollection.updateOne(foundWalletDetailDoc1, updateWalletDocOperation);
updateWalletDoc = new Document("identifier", "walletBalanceDistribution")
        .append("totalRTKBalanceForPool", foundWalletDetailDoc2.get("totalRTKBalanceForPool"))
        .append("lastCheckedBlockNumber", foundWalletDetailDoc2.get("lastCheckedBlockNumber"))
        .append("lastCheckedTransactionIndex", foundWalletDetailDoc2.get("lastCheckedTransactionIndex"))
        .append("balanceCollectedAsFees", foundWalletDetailDoc2.get("balanceCollectedAsFees"));
updateWalletDocOperation = new Document("$set", updateWalletDoc);

//////// TEMPORARY... TO BE REMOVED
Thread.sleep(5000);
clientSession.abortTransaction();  // Important Line 2
boolean abc = true;
if(abc) {
    return;
}
////////

Now, I excepted that once I call abortTransaction(), the collection would revert back to it's previous state as it was before //Important Line 1. But that doesn't happend. As I keep making operations, they get saved in MonogDB and do not get reverted when // Important line 2 completes execution.

(Just in case, everything is in try catch and there are no errors between any lines. The code successfully reaches the return statement.)

Also, if required, I am using the following maven dependency:-

<dependency>
    <groupId>org.mongodb</groupId>
    <artifactId>mongodb-driver-sync</artifactId>
    <version>4.2.0</version>
</dependency>

How to do this operation properly such that everything gets done, or nothing gets done (i.e. rollback/abort).

Upvotes: 0

Views: 3833

Answers (2)

Hokkyokusei
Hokkyokusei

Reputation: 1234

Correct answer was pretty simple...

(Found by referring to the link at the very bottom of @R2D2 's answer.)

(TL;DR :- Add clientSession as the first parameter in updateOne method).

All we had to do is this :-

        clientSession.startTransaction();  // Important Line 1.
        Document walletDetailDoc = new Document("identifier", "walletBalanceDistribution");
        Document foundWalletDetailDoc1 = (Document) walletDistributionCollection.find(walletDetailDoc).first();
        walletDetailDoc = new Document("identifier", to + "Backup");
        Document foundWalletDetailDoc2 = (Document) walletDistributionCollection.find(walletDetailDoc).first();
        walletDetailDoc = new Document("identifier", from + "Backup");
        Document foundWalletDetailDoc3 = (Document) walletDistributionCollection.find(walletDetailDoc).first();
        assert foundWalletDetailDoc1 != null;
        assert foundWalletDetailDoc2 != null;
        assert foundWalletDetailDoc3 != null;


        Bson updateWalletDoc = walletDetailDoc;
        Bson updateWalletDocOperation = new Document("$set", updateWalletDoc);
        walletDistributionCollection.updateOne(clientSession, foundWalletDetailDoc1, updateWalletDocOperation);
        updateWalletDoc = new Document("identifier", "walletBalanceDistribution")
                .append("totalRTKBalanceForPool", foundWalletDetailDoc2.get("totalRTKBalanceForPool"))
                .append("lastCheckedBlockNumber", foundWalletDetailDoc2.get("lastCheckedBlockNumber"))
                .append("lastCheckedTransactionIndex", foundWalletDetailDoc2.get("lastCheckedTransactionIndex"))
                .append("balanceCollectedAsFees", foundWalletDetailDoc2.get("balanceCollectedAsFees"));
        updateWalletDocOperation = new Document("$set", updateWalletDoc);
        
        //////// TEMPORARY... TO BE REMOVED
        Thread.sleep(5000);
        clientSession.abortTransaction();  // Important Line 2
        boolean abc = true;
        if(abc) {
            return;
        }
        ////////

Upvotes: 1

R2D2
R2D2

Reputation: 10707

You need to include the write operations inside the session transaction , example:

original state of collection:

 mongos> db.tra.find()
 { "_id" : ObjectId("601088bac5b64c7d32c73a8a"), "today" : ISODate("2021-01-26T21:25:14.835Z") }
 { "_id" : ObjectId("60108901c5b64c7d32c73a8b"), "today" : ISODate("2021-01-26T21:26:25.264Z") }
 mongos> 

1 Now you start session:

 session = db.getMongo().startSession()

2 Now you start transaction in the started session:

 mongos> session.startTransaction()

3 You insert test document to the collection in the transaction:

 mongos> session.getDatabase("test").tra.insert({a:"this will be aborted",today : new Date()})
 WriteResult({ "nInserted" : 1 })

4 Check the collection now , there is no inserted document(transaction is yet not commited):

 mongos> db.tra.find()
 { "_id" : ObjectId("601088bac5b64c7d32c73a8a"), "today" : ISODate("2021-01-26T21:25:14.835Z") }
 { "_id" : ObjectId("60108901c5b64c7d32c73a8b"), "today" : ISODate("2021-01-26T21:26:25.264Z") }

5 Now abort the transaction:

 mongos> session.abortTransaction()

6 As you can see nothing is inserted(transaction was aborted):

 mongos> db.tra.find()
{ "_id" : ObjectId("601088bac5b64c7d32c73a8a"), "today" : ISODate("2021-01-26T21:25:14.835Z") }
{ "_id" : ObjectId("60108901c5b64c7d32c73a8b"), "today" : ISODate("2021-01-26T21:26:25.264Z") }
mongos> 

Afcourse if you replace step 5 with session.commitTransaction() the transaction will be commited and you will see the operations applied to the collection.

There is nice java example here : https://www.mongodb.com/blog/post/java-and-mongodb-40-support-for-multidocument-acid-transactions

Upvotes: 2

Related Questions