缓存不一致 - 实体并不总是保留在缓存的集合中
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<>();
我遇到了 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<>();