This is somewhat of a continuation of Hibernate session thread safety. All of the details apply here as well. In simplified terms, execution follows the pattern of:
1. Read entity
2. Do expensive, easily parallelizable work
3. Persist changes
The entities are all configured for eager loading, and the session is not accessed at all during 2.
The work involved in 2
requires infrequent modification of a persistent collection. This is what I have now:
synchronized (parentEntity) {
parentEntity.getChildEntities().add(childEntity);
}
This works just fine, but I'm trying to "idiot-proof" this system and I'm looking for a way to move the concurrency control as far down into the persistence layer as I can. I've tried this in the dao:
@Transactional
public ParentEntity getParentEntityById(long id) {
ParentEntity parent = ...;
parent.setChildren(Collections.synchronizedSet(parent.getChildren()));
return parent;
}
Which results in org.hibernate.HibernateException: A collection with cascade="all-delete-orphan" was no longer referenced by the owning entity instance...
Does anybody have a way to introduce thread-safety to hibernate collections, or some other clean way to control concurrent access and modification in a way that doesn't require polluting the business logic?
Update- Here is what I ended up doing, per Pace's suggestion:
@Transactional
public ParentEntity getParentEntityById(long id) {
ParentEntity parent = ...;
currentSession().evict(parent);
parent.setChildren(Collections.synchronizedSet(parent.getChildren()));
return parent;
}
After the work is done, I save all of the children and call currentSession().merge(parent)
. Works like a charm!