【问题标题】:Retrieve all Foo from Hibernate second level cache without a query cache?在没有查询缓存的情况下从 Hibernate 二级缓存中检索所有 Foo?
【发布时间】:2009-08-19 19:00:53
【问题描述】:

在他出色的博文“Hibernate query cache considered harmful?”中,Alex Miller(来自 Terracotta Inc.)解释了为什么使用查询缓存会损害延迟和可扩展性。

我的问题是:是否可以为使用二级缓存而没有查询缓存的特定域对象类型编写“获取所有”DAO 方法?

这种方法我常用的代码形式涉及查询缓存,例如:

public List<Foo> getAllFoo()
{
    return (List<Foo>) getHibernateTemplate().execute(new HibernateCallback()
    {
        public Object doInHibernate(Session session)
        {
            Query q = session.createQuery("from Foo");
            // Cache the results in the query cache.
            q.setCacheable(true);
            return q.list();
        }
    });
}

我唯一模糊的想法是在某个单例域对象(也被缓存)上维护所有 Foo 的缓存集合。有没有更优雅的方式?

【问题讨论】:

  • 您的意思是从数据库中获取所有内容还是从当前缓存中获取所有内容?如果是前者,Hibernate 将使用普通的“从表”查询为您处理它。如果是后者,您可以访问缓存本身并对其进行迭代。
  • 后者(抱歉,如果问题标题中不清楚)。我将如何“获取缓存本身并对其进行迭代”?

标签: hibernate


【解决方案1】:

如果您使用的是 EhCacheProvider,您想要的是访问 CacheManager 成员变量。不幸的是,它是私有的,没有公共访问方法,因此我最终创建了自己的 EhCacheProvider 副本,该副本使用 CacheManager 的静态方法和公共静态方法来返回它。我假设您可以以相同的方式处理其他缓存提供程序,或者只实现 CacheProvider 接口。

一旦你有了 CacheManager,你就可以使用 cacheManager.getCache(class name) 来获得域(类)名的 Cache。这将返回一个缓存,您可以使用 cache.getKeys() 对其进行迭代。每个键都是一个 CacheKey,上面有实体 id,因此您可以使用 cache.get(key) 返回实际的实体。

如果您不介意绕过一些 Java 安全性并依赖于特定的 Hibernate 实现,那么另一个选项类似于(省略异常处理):

  EhCacheProvider cp = (EhCacheProvider)((SessionFactoryImpl)session.getSessionFactory()).getSettings().getCacheProvider()
  Field f = EhCacheProvider.class.getDeclaredField("manager");
  f.setAccessible(true);
  CacheManager cm = (CacheManager)f.get(cp);
  Cache c = cm.get(Entity.class);

【讨论】:

  • 有趣。像这样直接访问缓存,我​​是否会负责检查缓存是否已失效(例如,由于插入了另一条记录)并刷新缓存(如果有)?或者我什至必须通过检查时间戳缓存来自己处理失效?
  • 我不这么认为。调用 Cache.get 方法就像做一个正常的 Hibernate 加载,它会命中缓存,所以它会检查过期日期。所有这些代码所做的只是提前获取缓存中的键列表,如果它不在缓存中,则不会访问数据库。您需要在 get 之后进行一次空检查,以防它在您获得键列表和获得元素之间过期。
猜你喜欢
  • 2020-01-13
  • 2014-11-28
  • 2011-12-18
  • 1970-01-01
  • 2013-10-31
  • 2015-05-14
  • 2014-06-20
  • 1970-01-01
  • 2012-12-12
相关资源
最近更新 更多