缓存不一致 - 实体并不总是保留在缓存的集合中

Cache inconsistency - Entity not always persisted in cached Collection

我遇到了 Validation 实例被添加到 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);
    }

}

验证class:

@Entity
@Table
@Cacheable
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Validation extends AbstractEntity {
  //some properties
}

两个 class 都是 Cacheable 并应用了 READ_WRITE 策略。 Validation 的单向 Collection 也使用相同的策略进行缓存。

人们会期望当调用 addValidation(new Validation('userName')); 的读写事务提交时,新的 Validation 将在后续的只读事务中可见。奇怪的是,有时它确实有效,有时它不起作用...

第一笔交易总是成功;我们看到新的验证被保存在数据库中并且 Step 的版本 属性 (用于乐观锁定目的)得到增加。但有时,第二次读取事务包含一个 Step 实例和一个空的 Validation 集合...

我们的Hibernate缓存配置如下:

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

知道是什么导致了这种奇怪的(随机的)行为吗?

更新数据时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

因为您使用的是单向一对多关联,所以您最终会得到 Validation table 和 Step_validation link table 也。每当您 add/remove 一个验证时,您必须点击两个 table 并且效率较低。

我建议您在 Validation 实体中添加 @ManyToOne 面,并将 @OneToMany 面变成映射集合:

@OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true, mappedBy = "step")
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
private Set<Validation> validations = new HashSet<>();