2009-08-19 65 views
0

亞歷克斯米勒(Terracotta Inc.)在他出色的博客文章「Hibernate query cache considered harmful?」中解釋了爲什麼使用查詢緩存會對延遲和可伸縮性造成負面影響。從Hibernate二級緩存中檢索所有Foo而沒有查詢緩存?

我的問題是:是否有可能爲不使用查詢緩存而使用二級緩存的特定域對象類型編寫'get all'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緩存收集一些單域對象(也被緩存) 。有沒有更優雅的方式?

+0

你的意思是從數據庫中獲取全部或全部是目前在緩存中?如果是前者,Hibernate會用普通的「從表」查詢爲你處理。如果是後者,你可以到達緩存本身,只是遍歷它。 – 2009-08-20 03:11:42

+0

後者(抱歉,如果在問題標題中不明確)。我將如何「到達緩存本身並只是遍歷它」? – 2009-08-20 07:55:11

回答

1

如果您使用的是EhCacheProvider,那麼您需要訪問CacheManager成員變量。不幸的是,它是私有的,沒有公共訪問方法,所以我最終創建了自己的EhCacheProvider副本,它使用一個靜態的CacheManager和一個公共靜態方法來返回它。我假設你可以用同樣的方式處理其他緩存提供者,或者只是實現CacheProvider接口。

一旦你有了CacheManager,你就可以使用cacheManager.getCache(類名)獲得域(類)名稱的緩存。這將返回一個可以使用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); 
+0

有趣。通過像這樣直接訪問緩存,我​​是否會負責檢查緩存是否已失效(例如,由於插入了另一個記錄)並刷新緩存?或者我甚至必須通過檢查時間戳緩存來自己照顧失效? – 2009-08-21 08:42:06

+0

我不這麼認爲。調用Cache.get方法就像做一個正常的Hibernate負載一樣,命中緩存,以便檢查到期日期。所有這些代碼都在提前獲取緩存中的密鑰列表,如果數據庫不在緩存中,則不會訪問該數據庫。如果在獲取密鑰列表和獲取元素的時間之間到期,您會希望在獲取後進行空值檢查。 – 2009-08-21 14:10:56