我们在EhCache
(4.3.8.Final
)中使用Hibernate
作为二级缓存(4.3.8.Final
)进行查询(仅限读取主要表),实体和实体之间的集合。
所以你可以说第二级缓存是为了优化目的而集中使用的。
到目前为止,我们从未遇到过任何重大问题......
我们关于相关实体的持久性模型基本如下:
首先,我们有2个实体,其中有一个自然的亲子关系中的双向映射:
@Entity
@Table(...)
@Cacheable
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
public class Parent extends BaseEntity {
@Id
private long id;
@OneToMany(mappedBy="parent", fetch=FetchType.LAZY, cascade = CascadeType.REMOVE)
@Cache(usage=CacheConcurrencyStrategy.READ_WRITE)
private Set<Child> children;
// getters and setters
}
@Entity
@Table(...)
@Cacheable
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
public class Child extends BaseEntity {
@Id
private long id;
@ManyToOne(fetch = FetchType.LAZY, optional = false)
@JoinColumn(name = "parent_id", nullable = false)
private Parent parent;
// getters and setters
}
接下来我们有一些InvokingEntity
,它与Parent
实体的单向映射
@Entity
@Table(...)
@Cacheable
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
public class InvokingEntity extends BaseEntity {
@Id
private long id;
@Fetch(FetchMode.SUBSELECT)
@OneToMany(fetch = FetchType.LAZY, mappedBy = "invokingEntity", cascade = CascadeType.ALL, orphanRemoval = true)
@OrderBy("sequence asc")
@SortComparator(ParentBySequenceComparator.class)
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
private Set<Parent> parents = new TreeSet<>();
// getters and setters
}
所有Entities
从BaseEntity
延伸,其中包含id
和version
等常见属性,用于optimistic locking
目的。
接下来会发生什么:
ChildRepository
个应用程序删除所有Child
个实体,然后创建新实体;这发生在同一个交易中(trx1
):
删除方法的摘录:
public void deleteChildsById(List<Long> childIds) {
if (!childIds.isEmpty()) {
getSession().createQuery("delete Child as child where child.id in (:childIds)")
.setParameterList("childIds", childIds)
.setReadOnly(false)
.executeUpdate();
}
}
创建方法的摘录:
public void createChilds(List<Child> childs) {
for (Child child : childs) {
getSession().save(child);
}
}
之后,在第二个事务(trx2
)中,子实体由自然实体图遍历检索:
InvokingEntity invokingEntity = getSession.get(InvokingEntity.class, someId);
Collection<Child> childs = invokingEntity.getFirstParent().getChilds();
现在,问题是childs
集合有时是空的(在trx2
中)
我们可以通过Child
在数据库中清楚地看到多个trx1
实体。
所以2nd level cache
和DB之间显然不匹配。
同样,这个问题仅在大约10%的情况下发生。
同样不是trx2
总是执行4-5秒 AFTER trx1
。
可能导致这种情况的原因是什么?映射,配置或查询问题?
在Hibernate
中存在一个问题,其中2nd level cache
未被无效,但在早期版本上似乎已解决automatic L2 collection cache eviction when an element is added/updated/removed,而不是我们正在处理的问题。
为了完整起见,我在下面添加了ehcache
配置的摘录:
<defaultCache maxElementsInMemory="10000"
eternal="false"
timeToIdleSeconds="1800"
timeToLiveSeconds="3600"
overflowToDisk="true"
diskPersistent="false"
diskSpoolBufferSizeMB="10"
diskExpiryThreadIntervalSeconds="120"
memoryStoreEvictionPolicy="LRU">
</defaultCache>
如果没有清楚解释的话,请随时询问! 我们为所有建议开放!