2015-10-19 96 views
0

我的項目最近發現Hibernate可以採用多級關係並在單個連接HQL中提取它們,以生成我們所需的填充對象。我們喜歡這個功能,認爲它會超越懶惰的獲取情況。HQL加入查詢以提前獲取大量關係

問題是,我們遇到了一個情況,一個父母有大約十幾個直接關係,幾個子關係,其中幾個關係在幾個實例中有幾十行。其結果是一個相當大的交叉產品,導致hql幾乎永遠旋轉它的輪子。在我們放棄並殺死它之前,我們將日誌記錄數量提高到了11,並且看到了超過100000次迭代。

很清楚,雖然這種技術在某些情況下非常有用,但它對生活中的一切都有限制。但是,對於這一點,什麼是最好的執行選擇在休眠?我們不想懶惰地加載這些,因爲我們會陷入N + 1的情況,情況會更糟。

我理想地希望讓Hibernate預取所有行和細節,但一次只做一個關係,然後將正確的細節對象保存到正確的父對象,但我不知道它是否會這樣的事情。

對此提出建議?

UPDATE:

因此,我們得到生成此查詢的SQL,事實證明,我被誤診的問題。交叉產品並不是那麼龐大。我們直接在數據庫中運行相同的查詢,並在一秒鐘內返回500行。但是我們在hibernate日誌中看到了非常清晰的100K迭代。 Hibernate是否可能陷入人際關係或循環中?

或者,也許這應該作爲一個新的問題?

+0

看一看[JPA實體圖形](http://www.radcortez.com/jpa-entity-graphs/ )。通過這些,你可以向JPA提供者暗示你想要加載的東西。然後,智能(TM)提供商將找出一種減少SELECT數量的好方法,而不必交叉加入所有實體。 (Hibernate似乎比EclipseLink在這個優化上表現更好。) – JimmyB

回答

0

我們的團隊使用特殊策略與協會合作。集合是懶惰的,單一關係也是懶惰的,除了簡單結構的引用(例如一個國家參考)。我們使用fluent-hibernate來加載我們在具體情況下需要的東西。這僅僅是因爲流利的hibernate支持嵌套投影。你可以參考這個unit test看看複雜的對象網絡可以部分加載。從單元測試的代碼段

List<Root> roots = H.<Root> request(Root.class).proj(Root.ROOT_NAME) 
      .innerJoin("stationarFrom.stationar", "stationar") 
      .proj("stationar.name", "stationarFrom.stationar.name") 
      .eq(Root.ROOT_NAME, rootName).transform(Root.class).list(); 

參見

How to transform a flat result set using Hibernate