hibernate—存储库访问的缓存集合,无需设置

hibernate—存储库访问的缓存集合,无需设置,hibernate,caching,domain-driven-design,Hibernate,Caching,Domain Driven Design,通常在hibernate中,我们与HashSets有很多父/子关系。因此,父对象有一组子对象。可以使用hibernate集合缓存轻松地将其缓存在二级缓存中。向集合中添加或删除对象时,缓存将无效 现在我们要删除父对象上的集合关系。这是因为遵循DDD(域驱动设计)语义,子级不属于父级的聚合根。子级本身是聚合根。但是子类仍然与父类有关系 因此,我们开始使用存储库,通过以下方法访问子对象: public Set<Child> getChildren(Parent parent) {

通常在hibernate中,我们与
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的解释就是错误的。聚合根目录将按集合而不是存储库引用其子实体。如果子对象本身是聚合根,我认为您的方法是正确的(没有显式的子集合引用)。我已经更新了我的问题。