I have a parent-child-relationship where the parent holds the @version property and it should be incremented whenever the parent itself or any of it children changes.
@Entity class Parent{
@OneToMany(mappedBy = "parent", ...)
Set<Child> children;
@Version
int version;
}
@Entity class Child{
@ManyToOne
Parent parent;
}
To archive this I lock the parent in OPTIMISTIC_FORCE_INCREMENT mode, whenever I add, modify or delete a child.
entityManager.lock(parent, LockModeType.OPTIMISTIC_FORCE_INCREMENT);
// modify child
Immediately before the transaction completes, hibernate generates a statement like this
/* forced version increment */ update
"PARENT"
set
"VERSION"=?
where
"PARENT_ID"=?
and "VERSION"=?
The version in the database is correctly incremented whereas the 2nd-Level-Cache doesn't get updated. If I select the parent it will be loaded from 2nd-Level-Cache and I still get the old version, I could do a refresh on it or evict it from 2nd-Level-Cache, but it doesn't feel right, it just has to be updated in consistency to the database.
I tried Infinispan and EHCache which both behave the same so I think it is a hibernate problem.
This is also the reason, why the RootAware-pattern from Vlad Mihalcea is not working in combination with 2nd-Level-Cache. See https://vladmihalcea.com/how-to-increment-the-parent-entity-version-whenever-a-child-entity-gets-modified-with-jpa-and-hibernate/
See this comment: https://stackoverflow.com/a/31003719/9354242 As I in this comment suggested I added a @LastModifiedDate column to the parent and update it whenever I modify a child. Instead of OPTIMISTIC_FORCE_INCREMENT I will have to use just OPTIMISTIC as LockModeType and it is working, both 2nd-Level-Cache and database have the correct version number, but I don't think this is a very good workaround since every developer has to know about it and there is a huge probability someone somewhere will forget it. Also it is a bad thing to add such a column like this just as a workaround.
Thanks in advance
What is your cache strategy for the Parent class? Could it be READ_ONLY? Try adding a Cache-annotation
@Cache(usage = READ_WRITE)
@Entity
class Parent
... to your entity and see if situation improves!