簡體   English   中英

Hibernate @OneToOne 已加載,即使是懶惰的

[英]Hibernate @OneToOne loaded even though is lazy

我正在使用 Spring Boot 2.3、Spring 數據和 Hibernate。

我有以下實體

@Entity
@Getter
@Setter
@EqualsAndHashCode(of = "id")
public class User {

    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Id
    private Long id;

    private String name;

    @OneToOne(mappedBy = "user", fetch = FetchType.LAZY, cascade = CascadeType.REMOVE)
    private Address address;

    @Version
    private Long version;
}

@Entity
@Getter
@Setter
@EqualsAndHashCode(of = "id")
public class Address {

    @Id
    private Long id;

    private String fullAddress;

    @OneToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "id")
    @MapsId
    private User user;

    @Version
    private Long version;    
}

執行以下代碼時,將執行與用戶存儲庫相關的任何查詢(對我來說這是預期的行為)。

Address addressFromDb = addressRepository.findAll().get(0);
log.info("" + addressFromDb.getUser().getId());

// select address0_.id as id1_0_, address0_.full_address as full_add2_0_, address0_.version as version3_0_ from address address0_

但是當我執行以下代碼時,會有多個查詢,我不明白為什么。 顯然,從用戶到地址的FetchType.LAZY不受尊重。

User userFromDb = userRepository.findAll().get(0);

// select user0_.id as id1_4_, user0_.name as name2_4_, user0_.version as version3_4_ from user user0_
// select address0_.id as id1_0_0_, address0_.full_address as full_add2_0_0_, address0_.version as version3_0_0_ from address address0_ where address0_.id=?

我錯過了什么?

為了更有幫助和更清楚,我創建了以下github repo

Hibernate (或更具體地說是PersistenceContext )需要知道實體是否存在,以便它可以決定是為實體提供代理還是null 這不適用於XToMany關系,因為整個集合可以包裝在代理中,在特殊情況下它將為空。

還需要指出的是, FetchType只是對 JPa 實現的建議,不能保證在任何情況下都會實現。 您可以在此處閱讀有關@OneToOne的更多信息,尤其是在獲取策略方面:

雖然可以延遲獲取單向 @OneToOne 關聯,但雙向 @OneToOne 關聯的父端卻不能。 即使指定關聯不是可選的並且我們有 FetchType.LAZY,父端關聯的行為也類似於 FetchType.EAGER 關系。 EAGER fetching 很糟糕。

即使 FK 不是 NULL 並且父端通過可選屬性(例如 @OneToOne(mappedBy = "post", fetch = FetchType.LAZY, optional = false))知道其不可為空性,Hibernate 仍然會生成二級 select 語句。

對於每一個托管實體,Persistence Context 都需要實體類型和標識符,因此在加載父實體時必須知道子標識符,而找到關聯的 post_details 主鍵的唯一方法是執行二級查詢。

字節碼增強是唯一可行的解決方法。 但是,它僅在父端使用 @LazyToOne(LazyToOneOption.NO_PROXY) 注釋並且子端未使用 @MapsId 時才有效。

暫無
暫無

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

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