Skip to content

Optimistic locking mechanism "cascading" through relationships #2604

@zsoltkatona

Description

@zsoltkatona

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 @Reference instead 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.

Metadata

Metadata

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions