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

use*_*927 6 java caching hibernate jpa ehcache

我遇到一个问题,即在Validation实例上将一个Step实例添加到Collection .声明如下:

步骤类:

@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);
    }

}
Run Code Online (Sandbox Code Playgroud)

验证类:

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

这两个类都Cacheable采用了READ_WRITE策略.单向的Validations 集合也使用相同的策略进行缓存.

可以预料,当读写事务调用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
Run Code Online (Sandbox Code Playgroud)

知道造成这种奇怪(和随机)行为的原因是什么?

Vla*_*cea 1

Hibernate Collection Cache总是使现有条目无效,并且 Entity 和 Collection 缓存共享相同的AbstractReadWriteEhcacheAccessStrategy,因此在更新数据时会获取软锁

因为您使用的是单向一对多关联,所以您最终也会得到一个Validation表和一个 Step_validation 链接表。每当您添加/删除验证时,您都必须访问两个表,这效率较低。

我建议您@ManyToOneValidation实体中添加侧面并将@OneToMany侧面转换为映射集合:

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