Spring mongo thread safety

Viewed 1427

I am learning about spring boot & concurrency. I understand that when spring boot receives multiple request, it will spin up multiple threads to handle the request. I have a method here which accesses mongo. This method will save a new someResult (with probably some new values set by the caller). My question is if there are say 100 concurrent calls to my spring boot controller, and im getting someResult object, and setting the values and saving etc, will the values be inconsistent?

  public void upsert(SomeResult someResult) {
        String collection = this.SomeResultConfig.getCollectionSomeResultCollection();
        String queryStr = "{testingID : '%s'}";
        queryStr = String.format(queryStr, someResult.getTestingID());
        Query query = new BasicQuery(queryStr);
        List<SomeResult> someResultList = this.mongoOps.find(query, SomeResult.class, collection);
        if (someResult.size() != 0) {
            this.mongoOps.findAllAndRemove(query, collection);
        }
        this.mongoOps.save(someResult, collection);
    }
2 Answers

Yes, it is possible that 2 threads will read the result first, then do a modification and then each thread writes the modification into the database. The database state ends up with one of the values - the latter one, the earlier write is lost - this is called lost update phenomena.

Apart from using transactions with sufficient isolation level you can also use optimistic locking.

The @Version annotation provides syntax similar to that of JPA in the context of MongoDB and makes sure updates are only applied to documents with a matching version. Therefore, the actual value of the version property is added to the update query in such a way that the update does not have any effect if another operation altered the document in the meantime. In that case, an OptimisticLockingFailureException is thrown. The following example shows these features:

https://docs.spring.io/spring-data/mongodb/docs/current/reference/html/#mongo-template.optimistic-locking

In your code you can decide if you want to retry the whole operation if the exception is thrown or if to report the error to the user.

MongoDB document level operations are atomic. Thus, if multiple threads modify the same document, the resulting document will be some interleaving of those update operations. If those update operations update common values, the resulting value will be what was set with the last update, which is nondeterministic.

If however your update operations are multi-step operations (like read a document, modify it in memory, and rewrite it back), then when you write the document there is no guarantee that you are not overwriting the changes made by another thread. For these kinds of updates, consider using mongo transactions so the read-update operation makes sure what you update is what you read.

If multiple threads are working on different documents you don't have any of these problems.

Related