2010-08-31 93 views
2

我們,我們需要一個Hibernate會話,我知道加載的所有實體的唯一途徑過程中加載實體的整個表的所有實體是通過HQL查詢:休眠裝載利用第一或第二級緩存

public <T> List<T> getAllEntities(final Class<T> entityClass) { 
    if (null == entityClass) 
     throw new IllegalArgumentException("entityClass can't be null"); 

    List<T> list = castResultList(createQuery(
      "select e from " + entityClass.getSimpleName() + " e ").list()); 


    return list; 
} 

我們使用EHcache進行二級緩存。

問題在於,這被稱爲100次在給定的交易會話中佔用了相當一部分總時間。有什麼辦法可以加載給定類型的所有實體(加載整個表),並且還能從第一級會話緩存或第二級ehcache中受益。

我們被告知要遠離查詢緩存,因爲它們的潛在性能損失與其收益相關。 * Hibernate Query Cache considered harmful

儘管我們現在正在執行性能分析,所以可能是時候嘗試啓用查詢緩存。

+1

爲什麼您的代碼首先在同一個事務中重新加載整個表100次?如果是因爲其他線程可能正在插入,那麼即使您以某種不可思議的方式重寫代碼以使用它們,L1和L2緩存也不能做太多的事情來幫助您。 – Affe 2010-08-31 23:31:49

+0

它是一個靜態表(每24小時至少靜態),更多的是,在給定的transacation中該方法被稱爲100次,我們可以輕鬆地在該DAO中「緩存」該事務的方法,但我很好奇,如果我正在重新創建已經完成的緩存,如果我以不同的方式加載表。 – Dougnukem 2010-09-01 18:04:06

回答

0

我們最終解決這個問題的方法是將主鍵存儲在我們需要加載的表中的所有實體(因爲他們是模板數據,沒有新的模板被添加/刪除)。

然後,我們可以使用這個主鍵列表來查找每個實體並利用Hibernates第一和第二級緩存。

1

對於「獲取整個表」的問題,L1和L2緩存無法幫助您。

L1緩存裝備不足,因爲如果別人插入了某些東西,它不在那裏。 (您可能「知道」在系統的業務規則中沒有其他人會這樣做,但Hibernate會話不會)。因此,您必須查看數據庫以確保安全。

有了L2緩存,事情可能已經過期或刷新自從上次有人把表放在那裏。這可以由緩存提供者支配,甚至可以通過一個MBean在外部完成。因此,Hibernate在任何時候都無法真正瞭解該類型的緩存中的內容是否代表該表的全部內容。再次,你必須在數據庫中查看一下。

由於您對此實體有特殊的知識(從未創建過新的實體),因此沒有實際的方法來傳遞L1或L2緩存,因此您需要使用由Hibernate提供的工具關於結果集的特殊業務規則級知識,查詢緩存或自己緩存信息。

-

如果你真的想在L2高速緩存,理論上你可以做一個集合的表成員的所有實體上的一些其他虛假的實體,然後啓用緩存的收集和管理偷偷它在DAO中。我不認爲這可能是值得在你的代碼中有這種奇怪的東西:)

1

當且僅當基礎表經常變化時,查詢緩存才被認爲是有害的。在你的情況下,表格每天更換一次。所以查詢會在緩存中保持24小時。相信我:使用它的查詢緩存。這是查詢緩存的完美用例。

有害查詢緩存示例:如果您有一個用戶表,並且您使用「來自User where username = ...」的查詢緩存,那麼每次修改用戶表時,此查詢都會從緩存中逐出(另一個用戶更改/刪除他的帳戶)。所以對這個表的任何修改都會觸發緩存逐出。改善這種情況的唯一方法是用自然標識查詢,但這是另一回事。

如果您知道您的表格每天只能修改一次,那麼查詢緩存將只會每天驅逐一次!

但修改表格時要注意你的邏輯。如果你通過休眠來實現,一切都很好。如果您使用直接查詢,則必須告訴hibernate您已修改表(類似query.addSynchronizedEntity(..))。如果通過shell腳本執行此操作,則需要調整基礎緩存區域的生存時間。

您的答案是通過重新實現查詢緩存的方式,因爲查詢緩存只是緩存了id列表。在L1/L2緩存中查找實際對象。所以當你使用查詢緩存時你仍然需要緩存實體。

請將此標記爲正確答案,以供進一步參考。