簡體   English   中英

使用hibernate.enable_lazy_load_no_trans解決Hibernate Lazy-Init問題

[英]Solve Hibernate Lazy-Init issue with hibernate.enable_lazy_load_no_trans

我一直患有臭名昭着的hibernate異常

org.hibernate.LazyInitializationException: could not initialize proxy - no Session

現在社區正在歡呼

<property name="hibernate.enable_lazy_load_no_trans" value="true"/>

說它解決了問題,但小心使用它

他們的意思是謹慎使用它? 這個屬性實際上做了什么?

請給我任何見解。 提前致謝。

這種方法的問題在於你可以獲得N + 1效果。

想象一下,你有以下實體:

public class Person{
    @OneToMany // default to lazy
    private List<Order> orderList;
}

如果您有一個返回10K人的報告,並且如果在此報告中您執行代碼person.getOrderList()則JPA / Hibernate將執行10K查詢。 這是N + 1效果,您將無法控制將要執行的所有查詢。

現在想象訂單如下:

public class Order{
    @OneToMany // default to lazy
    private List<EmailSent> emailSentList;
}

現在想象一下,您對person.getOrderList()進行了迭代,並且對於每個Order order您將執行order.getEmailSentList() 你現在能看到問題嗎?

對於LazyInitializationException,您可以使用一些解決方案:

  • 使用OpenInSessionInView方法。 您將需要創建一個將打開和關閉事務的WebFilter。 問題是N + 1效應。
  • 使用hibernate的hibernate.enable_lazy_load_no_trans配置,如果需要,您將無法將項目移植到其他JPA提供程序。 你也可以有N + 1效果。
  • 使用名為PersistenceContext Extended的EJB功能。 有了這個,您將保持幾個事務的上下文打開。 問題是:N + 1效應可能發生,使用大量服務器內存(實體將保持管理)
  • 在查詢中使用FETCH。 使用這種方法,您可以執行JPQL / HQL,例如: select p from Person p join fetch p.orderList 使用此查詢,您將從數據庫加載列表,並且不會產生N + 1效果。 問題是你需要為每個案例編寫一個JPQL。

如果您仍有任何問題,請查看以下鏈接:

這違背了我們如何利用Hibernate利用Session概念實現可重復讀取語義的優勢。 首次加載對象時,如果在會話的生命周期內再次引用該對象,則返回相同的對象IRRESPECTIVE,該對象是否在DB中發生了更改。 這是hibernate自動提供的可重復讀取語義。

使用此設置,您沒有提供此保證的會話,因此,如果您現在訪問此數據,您將獲得最新版本的數據。

這可能沒問題。 但是考慮這個對象在某個地方長時間保存並且數據發生了很大變化的情況,因此延遲獲取的數據與會話處於活動狀態時已經加載的數據有很大不同。 這是你需要關注的。

如果您的程序不受以下影響,您可以安全地使用此設置:在會話期間已經提取的數據與將從會話中拉出的數據失效的情況有多陳舊

但是如果這個( 你的程序暴露於計時問題,它可能正常工作一次並且失敗了另一次 )是一個問題,那么在會話期間獲取所有必要的數據。

解決LazyInitializationException的最佳方法是在實體查詢中使用JOIN FETCH指令。

EAGER加載對性能不利。 此外,還有反模式,如:

你應該永遠不要使用它,因為它們要求為UI呈現打開數據庫連接(在視圖中打開會話),或者在初始持久化上下文之外獲取的每個惰性關聯都需要數據庫連接( hibernate.enable_lazy_load_no_trans ) 。

有時,您甚至不需要實體, DTO投影甚至更好

可能是因為有更好的解決方案,比如@Transactional ,其中打開和關閉會話遵循一個非常常見的模式“打開會話然后將所有內容包裝在try-catch-finally中; catch回滾並最終關閉會話”。 此注釋通常位於Web應用程序和服務的請求級別。

或者,如果您需要更精細的控制,可以使用SessionFactory手動打開會話。

正如其他人所提到的,延遲加載是你需要注意的事情。 它不是一顆銀彈,但它可能非常有用。 通常,如果您的應用程序設計為包含許多小請求,則可以。

渴望加載也可能非常糟糕。 例如,當您的對象模型具有許多多對多關系時,但您的請求不會使用多個深度的數據。

或者你現在可以忘記整件事。 使用延遲加載直到它成為一個問題。 如果確實如此,那么無論如何你都會更好地使用Mybatis。

暫無
暫無

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

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