Reputation: 197
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
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