i will explain the situation briefly,
i have 2 entities, parent and child with OneToMany
list of child in the parent and ManyToOne
reference to the parent from the child. i am cascading all operations including orphan removal from parent to childs.
i have a scheduled task executed every 5 minutes, retrieving the parent entity, perform some logic, changing the child entity and saves the parent back to the DB.
additionally there is a REST endpoint for parent modification. first checks if there is a parent with id X in the DB if there is no such parent it creates and saves it. otherwise it retrieving existing parent removing all it's existing childs, adding new child and saves parent back to DB.
the problem occurs when those 2 different threads invoked almost exactly the same time.
scheduled task retrieves old entity.
rest endpoint retrieves old entity.
rest endpoint performs childs removal and new child addition.
rest saves to db.
scheduled task saves old parent to db with old childs modified.
the result i get is i have all previous childs modified new child inserted by rest endpoint instead of just the new child. i want to get rid of the old childs.
this is very rare occasion but it happened to me twice this year, how i can avoid it?
CodePudding user response:
Use locking. Depending on your needs pessimistic or optimistic.
optimistic
Add a version field to your entities like
@Version
private int version;
pessimistic
Use the appropiate lock mode for example
entityManager.find(Person.class, id, LockModeType.PESSIMISTIC_WRITE);
Please also read the Hibernate documentation:
https://docs.jboss.org/hibernate/orm/5.5/userguide/html_single/Hibernate_User_Guide.html#locking