我的問題是,Hibernate加載OneToOne關聯對每個null關係執行+1選擇。Hibernate OneToOne(可選= true)與FetchMode.JOIN嘗試重新選擇空值
實體例如:
@Entity
class SideBlue {
@Column(nullable = false)
private Integer timestamp;
@OneToOne(optional=true)
@JoinColumn(name="timestamp", referenceColumn="timestamp", insertable = false, updatable = false)
SideRed redSide;
}
@Entity
class SideRed {
@Column(nullable = false)
private Integer timestamp;
}
(這是一個傳統的數據庫模式,所以對數據庫的修改是不允許的)
查詢例如:
CriteriaBuilder builder... CriteriaQuery query...
Root<SideBlue> root = query.from(SideBlue.class);
root.fetch(SideBlue_.sideRed, JoinType.LEFT);
entityManager().createQuery(query).getResultList();
結果: 如果所有的藍方實體有一個紅色的一面,一切正常,所以休眠只對數據庫執行一個查詢,以檢索任何實體。
但是,如果藍色邊實體沒有關聯紅色邊實體,hibernate會嘗試再次找到另一邊。對於每個null redSide屬性,Hibernate sql註釋說'/ *加載RedSide */select ...'。
如何跳過這第二個選擇?
實際問題出現在延遲不是非常低的時候。如果我嘗試選擇100萬行,並且1/3有空的「紅色側」,則總延遲時間是一個真正的問題。
編輯:
這是調試日誌查詢
10:04:32.812 [main] DEBUG org.hibernate.loader.Loader - Result set row: 0
10:04:32.815 [main] DEBUG org.hibernate.loader.Loader - Result row: EntityKey[SideBlue#1269721], EntityKey[SideRed#3620564]
10:04:32.833 [main] DEBUG org.hibernate.loader.Loader - Result set row: 1
10:04:32.833 [main] DEBUG org.hibernate.loader.Loader - Result row: EntityKey[SideBlue#1269776], null
第一行包含了藍色和紅色的邊,但第二個只藍方。所以冬眠必須知道相關的紅邊不存在。但是,所有結果行處理...
10:04:33.083 [main] DEBUG o.h.engine.internal.TwoPhaseLoad - Resolving associations for [BlueSide#1269721]
10:04:33.084 [main] DEBUG org.hibernate.loader.Loader - Loading entity: [RedSide#component[timestamp]{timestamp=1338937390}]
10:04:33.084 [main] DEBUG org.hibernate.SQL - /* load RedSide */ select ...
! Nothing really loaded because the previous SQL return empty result set, again !
10:04:33.211 [main] DEBUG org.hibernate.loader.Loader - Done entity load
你的例子很讓人困惑,它上面有@JoinColumn標註的一面根據定義是關係的所有者。 – Affe
我的錯誤。我重新定義/改進了實體定義。這是我實體的簡化版本,但我認爲這已經足夠了。數據庫在雙方時間戳之間沒有FK。 –