簡體   English   中英

避免n + 1選擇與緩存Hibernate關聯或緩存集合作為一個整體

[英]Avoiding n+1 selects with Cached Hibernate Associations or Caching Collections as a whole

我有一對多的關系:父記錄與n子記錄。 這些記錄經常使用和只讀,是緩存的理想選擇。

這是我的Hibernate映射的近似值:

`<class name="Parent" table="Parent>
   <cache usage="read-only"/>
   <id name="primary_key"/>
   <property name="natural_key"/>

   <set name="children" lazy="false" fetch="join">
      <cache usage="read-only"/>
      <key-column name="parent_id"/>
      <one-to-many class="Child"/>
   </set>
</class>

<class name="Child" table="Child">
   <cache usage="read-only"/>
   <id name="primary_key"/>
   <property name="parent_id"/>
</class>`

我經常通過自然鍵而不是主鍵來獲取Parent,因此我需要啟用查詢緩存以利用二級緩存(我使用ehcache)。

這是問題所在:當我獲取父級並在查詢緩存中獲得命中時,它將成為“按主鍵提取”查詢。 對於我的一對多的“一”結尾來說這很好。 如果在緩存中找不到Parent,則從DB中獲取它。 如果在緩存中找不到我的n個子記錄,Hibernate會使用n個后續選擇查詢來獲取它們。 N + 1選擇問題。

我想要的是一種緩存由parent_id鍵入的Child對象集合的方法。 我希望Hibernate在整個緩存中查找我的集合,而不是作為一堆單獨的記錄。 如果找不到集合,我希望Hibernate使用1 select語句獲取集合 - 使用parent_id = x獲取所有Child。

從Hibernate + ehcache這個問題太多了嗎?

我找到了自己的答案 - 可以配置Hibernate + ehcache來執行我上面描述的操作。

通過將我的Child聲明為值類型而不是實體類型(我相信這些是Hibernate社區使用的術語),我基本上可以將我的Child視為Parent的一個組件而不是一個單獨的實體。 這是我修改后的映射的一個例子:

<class name="Parent" table="Parent">
   <cache usage="read-only"/>
   <id name="primary_key"/>
   <property name="natural_key"/>

   <set name="children" lazy="false" fetch="join" table="Child">
      <cache usage="read-only"/>
      <key-column name="parent_id"/>
      <composite-element class="Child">
         <property name="property1" column="PROP1" type="string">
         <property name="property2" column="PROP2" type="string">
      </composite-element>
   </set>
</class>

在此配置下,我的Child對象的行為與以前相比略有不同 - 現在沒有為Child定義單獨的主鍵,沒有共享引用,也沒有可空字段/列。 有關詳細信息,請參閱Hibernate文檔

我的父母和孩子都是只讀的,我真的只想通過父母訪問Child的實例 - 我不使用Child獨立於Parent,因此值類型處理非常適合我的用例。

對我來說最大的勝利是如何在我的新配置下緩存該集合。 集合緩存現在將我的集合整體緩存,由parent_id鍵入。 我的集合中的某些(但不是全部)不再可能位於緩存中。 該集合被緩存並作為一個整體逐出。 更重要的是,如果Hibernate在二級緩存中尋找我的集合並得到一個未命中,它會通過一個選擇查詢從數據庫中獲取整個集合。

這是我的ehcache配置:

 <ehcache>
    <cache name="query.Parent"
        maxElementsInMemory="10"
        eternal="false"
        overflowToDisk="false"
        timeToIdleSeconds="0"
        timeToLiveSeconds="43200" 
    </cache>
    <cache name="Parent"
        maxElementsInMemory="10"
        eternal="false"
        overflowToDisk="false"
        timeToIdleSeconds="0"
        timeToLiveSeconds="43200" 
    </cache>
    <cache name="Parent.children"
        maxElementsInMemory="10"
        eternal="false"
        overflowToDisk="false"
        timeToIdleSeconds="0"
        timeToLiveSeconds="43200" 
    </cache>
<ehcache>

希望這個例子可以幫助別人。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM