amit.shipra
amit.shipra

Reputation: 197

MongoDB Transactions: WriteConflict Error

Environment:

We are using MongoDB Transactions using the callback API. Same happens with Core API as well.

Sample:

    private ThreadLocal<MongoOperations> sessionMongoTemplate;

    try (final ClientSession session = getClientSession()) {
       this.sessionMongoTemplate = ThreadLocal.withInitial(() -> getMongoOperations().withSession(session));

       session.withTransaction(() -> {
           // do some work
           // call a method which does (sessionMongoTemplate.get().insert(entity);) 
           // (this throws WriteConflict Error)
       });
   } 

Error:

com.mongodb.MongoCommandException: Command failed with error 112 (WriteConflict): 'WriteConflict error: this operation conflicted with another operation. Please retry your operation or multi-document transaction.' on server abc.mongodb.net:1234. The full response is { "errorLabels": [ "TransientTransactionError" ], "ok": 0, "errmsg": "WriteConflict error: this operation conflicted with another operation. Please retry your operation or multi-document transaction.", "code": 112, "codeName": "WriteConflict"

Query:
We associated MongoOperations/Template with ClientSession already. That session opened a transaction. However, when code uses the SessionScoped MongoOperations, it fails as if it has no knowledge of opened transaction.

Can we not use this approach?

As per the example in : https://docs.mongodb.com/v4.2/core/transactions-in-applications/ within transaction body, we used MongoClient and it works fine. Can we not use SessionScoped MongoTemplate?

Upvotes: 4

Views: 11535

Answers (1)

barrypicker
barrypicker

Reputation: 10088

So, after some digging, this is what I think is happening...

With a database operation (command, such as insert or update), if not in an ACID transaction, conflicting operations (the second session in your example) will block behind the current operation's commit with a retry. Keep in mind, outside of ACID transactions MongoDB has document level atomicity.

But, with multi-document transactions, the behavior is different. If a writeConflict is encountered it fails immediately. The strategy is designed this way to allow your application to detect this condition, then wait X milliseconds and retry N times, where X and N are your comfort levels.

The parameter you are setting has nothing to do with how long a second session will block and wait, but has to do with how long the system is allowed to wait before a lock can be established. The default is 5ms. Your example shows 3 seconds (3000ms). Presumably you were referring to the lock on session number 2 - how long you allow it to take to acquire a lock. The problem is that the writeConflict was detected before any attempt to acquire a lock, because in ACID transactions the application is expected to perform the wait, not the driver.

Upvotes: 5

Related Questions