I'm going through Spring Data MongoDB - Reference Documentation and I'm finding the examples to be a bit too simplistic.
In particular I'm trying to understand how to handle stale data in concurrent environments. For instance, imagine I have the following entity:
public class Person {
private final String username;
private final String firstname;
private final String lastname;
[...]
}
Now if I use CrudRepository
to save/update/remove my entities, then imagine a scenario in which two threads retrieve the same entity, one of them removes it, and the other one updates its lastname
field. If the delete
call completes before the save
call then my entity will be removed and then re-created, when the expected behaviour would be for the save
operation to fail.
So far I've seen two options for getting around this issue:
@Version
annotation. Could not find any documentation saying Spring Data supports optimistic locking in MongoDB using versioned documents. If anyone can point me to a link it'd be appreciated.Use MongoOperations.findAndModify
and fail if it returns null
. The downside to this approach is that I can no longer implement my repository API to have "get entity" and "save updated entity" kind of semantics. e.g.:
User user = userRepository.findByUsername("uniqueUsername");
user.setLastName("Archer");
userRepository.update(user);
I would have to push some of this to the repository I guess:
userRepository.updateLastname("uniqueUsername", "Archer");
But I'm a little bit worried my repository interfaces will grow uncontrollably if every type of update I want to do requires a new method.
I realise I haven't actually stated a question yet, so here it goes: what's the best-practice for designing an application using Spring Data for MongoDB?
Mongo has had a lot of work done to strengthen its distributed story (see the Jepsen analysis), it has no built-in support for optimistic concurrency control at a document level.
In order to use optimistic locking, we need to have an entity including a property with @Version annotation. While using it, each transaction that reads data holds the value of the version property. Before the transaction wants to make an update, it checks the version property again.
Yes, DataNucleus JPA allows it, as well as to many other databases.
Optimistic locking is a bit different. Instead of denying something to others, we make sure we are not the ones breaking the data. This is ensured by keeping track of the object's version we are working with and checking, that we only update the DB record if it's version hasn't changed.
Using @org.springframework.data.annotation.Version
on a property should do the trick. I've created DATAMONGO-1275 to improve the documentation on that.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With