- Notifications
You must be signed in to change notification settings - Fork 619
Description
I'd like to ask you a quick question that I wasn't able to figure out myself after days of googling and reading the SDN reference.
We have a class and a node label, let's call it Dog and in that class we model a relationship to another class/label called Person. A Dog has a single owner who is a Person, let's say. We first create a Person and then a Dog on which we set the owner to an existing Person. Nothing weird so far.
However when we add optimistic locking for both the Dog and the Person (using @Version) then we run into a problem: when we save the Dog, then the Person's version also gets incremented, though that object isn't changed. In fact, it's set in a similar way to this:
public void save(Dog dog) { DogGMO dogGMO = dogMapper.convert(dog); PersonGMO personGMO = personRepository.findById(dog.getPerson().getId()); dogGMO.setPerson(personGMO); dogRepository.save(dogGMO); } The problem it causes is that if there are more users/threads creating Dogs, then many of them will receive an optimistic locking exception:
org.springframework.dao.OptimisticLockingFailureException: An entity with the required version does not exist. at org.springframework.data.neo4j.core.Neo4jTemplate.saveRelatedNode(Neo4jTemplate.java:858) at org.springframework.data.neo4j.core.Neo4jTemplate.lambda$processNestedRelations$27(Neo4jTemplate.java:768) at org.springframework.data.mapping.model.BasicPersistentEntity.doWithAssociations(BasicPersistentEntity.java:387) at org.springframework.data.neo4j.core.Neo4jTemplate.processNestedRelations(Neo4jTemplate.java:677) at org.springframework.data.neo4j.core.Neo4jTemplate.processRelations(Neo4jTemplate.java:662) at org.springframework.data.neo4j.core.Neo4jTemplate.saveImpl(Neo4jTemplate.java:406) at org.springframework.data.neo4j.core.Neo4jTemplate.save(Neo4jTemplate.java:321) at org.springframework.data.neo4j.repository.support.SimpleNeo4jRepository.save(SimpleNeo4jRepository.java:117) ... My question is this: is there a way to prevent that the Person's version is incremented but still have the relationship modeled at the OGM level?
Couple things I already tried:
- I tried double-mapping (Person, ImmutablePerson) but 2 classes can't have the same
@Node("Person")annotation, so this didn't work, - I tried annotating the Dog's person field with
@ReadOnlyProperty, but then the relationship is not persisted (which is what I expected, but I'm mentioning it anyway just for completeness), - I tried
@Referenceinstead of@ReadOnlyProperty, it doesn't seem to have any effect, - I tried synchronizing the save(Dog dog) method, and this works, but our service is expected to run with multiple replicas, so that won't scale,
- I tried modeling the relationship with a separate class that is annotated with
@RelationshipProperties, but the Person's version still gets incremented, i.e. that doesn't stop the cascading, - I updated Spring Data Neo4j to 6.3.3, Spring Data Commons to 2.7.3 and the Neo4j Java driver to 4.4.9 (i.e. all latest and greatest), but these didn't help either, I get the same opt. lock exception.
I don't know if this is by design or it's rather a bug. If it's by design, then it would be beneficial to have an annotation that stops the cascading, i.e. marks the target node of a relationship as read-only (and every node and relationship starting from that target node potentially).
Any help is appreciated.