hibernate—存储库访问的缓存集合,无需设置
通常在hibernate中,我们与hibernate—存储库访问的缓存集合,无需设置,hibernate,caching,domain-driven-design,Hibernate,Caching,Domain Driven Design,通常在hibernate中,我们与HashSets有很多父/子关系。因此,父对象有一组子对象。可以使用hibernate集合缓存轻松地将其缓存在二级缓存中。向集合中添加或删除对象时,缓存将无效 现在我们要删除父对象上的集合关系。这是因为遵循DDD(域驱动设计)语义,子级不属于父级的聚合根。子级本身是聚合根。但是子类仍然与父类有关系 因此,我们开始使用存储库,通过以下方法访问子对象: public Set<Child> getChildren(Parent parent) {
HashSet
s有很多父/子关系。因此,父对象有一组子对象。可以使用hibernate集合缓存轻松地将其缓存在二级缓存中。向集合中添加或删除对象时,缓存将无效
现在我们要删除父对象上的集合关系。这是因为遵循DDD(域驱动设计)语义,子级不属于父级的聚合根。子级本身是聚合根。但是子类仍然与父类有关系 因此,我们开始使用存储库,通过以下方法访问子对象:
public Set<Child> getChildren(Parent parent) {
Criteria criteria = getSession().createCriteria(Child.class);
criteria.add(Restrictions.naturalId().set("parent", parent));
criteria.setCacheable(true); // does not work here!
return criteria.list();
}
public abstract class CollectionRepositoryHibernate<T extends PersistableEntity, E extends PersistableEntity> extends StandardRepositoryHibernate<T> implements
CollectionRepository<T, E>
{
private Class<T> entityClass = getGenericClass();
private Class<E> parentClass = getGenericParentClass();
@Override
public void save ( T persistableEntity )
{
evictCache(persistableEntity);
super.save(persistableEntity);
}
@Override
@SuppressWarnings("unchecked")
public List<T> getCollection ( E persistableEntity )
{
return getNaturalCollectionCriteria(persistableEntity).list();
}
protected Criteria getNaturalCollectionCriteria ( E persistableEntity )
{
Criteria criteria = getSession().createCriteria(entityClass);
criteria.add(Restrictions.naturalId().set(getPropertyName(), persistableEntity));
criteria.setCacheable(true);
criteria.setCacheRegion(getCacheRegion(persistableEntity.getId()));
return criteria;
}
private String getPropertyName ( )
{
ClassMetadata classMetadata = getSession().getSessionFactory().getClassMetadata(entityClass);
int[] naturalIdentifierProperties = classMetadata.getNaturalIdentifierProperties();
String[] propertyNames = classMetadata.getPropertyNames();
for (int i : naturalIdentifierProperties)
{
String propertyName = propertyNames[i];
try
{
Field field = entityClass.getDeclaredField(propertyName);
Class<?> type = field.getType();
if (type.equals(parentClass))
{
return propertyName;
}
}
catch (Exception e)
{
e.printStackTrace();
}
}
throw new IllegalStateException("No property name found");
}
private void evictCache ( T persistableEntity )
{
Cache cache = getSession().getSessionFactory().getCache();
String cacheRegion = getCacheRegion(getCollectionId(persistableEntity));
cache.evictQueryRegion(cacheRegion);
}
protected String getCacheRegion ( Integer id )
{
return entityClass + "#" + id;
}
@Override
public void delete ( T persistableEntity )
{
evictCache(persistableEntity);
super.delete(persistableEntity);
}
protected Integer getCollectionId ( T persistableEntity )
{
try
{
Field field = persistableEntity.getClass().getDeclaredField(getPropertyName());
field.setAccessible(true);
PersistableEntity parentEntity = (PersistableEntity) field.get(persistableEntity);
return parentEntity.getId();
}
catch (Exception e)
{
throw new IllegalStateException("no collection id found, e");
}
}
@SuppressWarnings("unchecked")
protected Class<E> getGenericParentClass ( )
{
Class<E> result = null;
Type type = this.getClass().getGenericSuperclass();
if (type instanceof ParameterizedType)
{
ParameterizedType pt = (ParameterizedType) type;
Type[] fieldArgTypes = pt.getActualTypeArguments();
result = (Class<E>) fieldArgTypes[1];
}
return result;
}
}
我们在这里使用的技巧是每个集合有一个缓存区域。
当涉及到保存或删除时,我们会逐出这个缓存区域。它工作正常,但有一些缺点:
- 我们需要很多缓存区域。到目前为止,我们不知道是否有一些限制或性能方面的考虑
- 因为缓存区域的名称在您无法配置缓存区域之前是未知的,例如设置最大元素数或生存时间
您知道一种正确的方法可以使集合缓存不映射到集合中的父/子关系吗?如果父对象是Order,子对象是OrderLine,那么您对DDD的解释就是错误的。聚合根目录将按集合而不是存储库引用其子实体。如果子对象本身是聚合根,我认为您的方法是正确的(没有显式的子集合引用)。我已经更新了我的问题。