I'm having an issue where a Validation
instance is added to a Collection on a Step
instance.
Declaration is as follows:
Step class:
@Entity
@Table
@Cacheable
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
public class Step extends AbstractEntity implements ValidatableStep {
@OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true)
@JoinColumn(name = "step_id", nullable = false)
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
private Set<Validation> validations = new HashSet<>();
@Override
public void addValidation(Validation validation) {
// do some stuff
...
// add validation instance to collection
getValidations().add(validation);
}
}
Validation class:
@Entity
@Table
@Cacheable
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Validation extends AbstractEntity {
//some properties
}
Both classes are Cacheable
with a READ_WRITE
strategy applied. The unidirectional Collection of Validation
s are also cached with same strategy.
One would expect when a read-write transaction that invokes addValidation(new Validation('userName'));
commits, the new Validation
would be visible in a subsequent read-only transaction. The weird thing is that sometimes it does work and sometimes it doesn't work...
The first transaction always succeeds; we see the new validation being persisted in database and Step
's version property (for optimistic locking puposes) getting incremented. But sometimes, the 2nd read transaction contains a Step
instance with an empty Validation
Collection...
Our Hibernate caching config is as follows:
hibernate.cache.use_second_level_cache = true
hibernate.cache.use_query_cache = true
hibernate.cache.region.factory_class = org.hibernate.cache.ehcache.SingletonEhCacheRegionFactory
hibernate.cache.provider_configuration_file_resource_path = classpath:ehcache.xml
net.sf.ehcache.hibernate.cache_lock_timeout = 10000
Any idea what's causing this weird (and random) behavior?
The Hibernate Collection Cache always invalidates existing entries and both the Entity and the Collection caches are sharing the same AbstractReadWriteEhcacheAccessStrategy, so a soft-lock is acquired when updating data.
Because you are using a unidirectional one-to-many association, you will end up with a
Validation
table and a Step_validation link table too. Whenever you add/remove a Validation you have to hit two tables and that's less efficient.I suggest you adding the
@ManyToOne
side in theValidation
entity and turn the@OneToMany
side into a mapped-by collection: