經典錯誤訊息:
org.hibernate.LazyInitializationException: could not initialize proxy - the owning Session was closed
發生原因:嘗試存取延遲載入的關聯物件或集合時,原本的 Hibernate Session 已經關閉,導致無法發送 SQL 查詢資料庫。
許多開發者直接在所有 <many-to-one>、<one-to-one>、<set> 上設定 lazy="false",雖能暫時解決問題,但會造成過度載入、效能低落,且違背 ORM 設計初衷。
在 Web 環境中採用 Open Session in View 模式,透過 Filter 或 Interceptor 讓 Session 保持開啟直到視圖渲染完成。Spring 提供 OpenSessionInViewFilter 即可輕鬆實現。
使用 Hibernate.initialize(proxy) 或在查詢時加入 FETCH JOIN、@NamedEntityGraph、EntityGraph 強制即時載入關聯資料,避免後續存取觸發例外。
在 Service 層將 Entity 轉換為 DTO 時,主動觸發所有需要的延遲屬性載入,Controller 僅操作已脫離持久化上下文的 DTO,徹底避免 LazyInitializationException。
// HQL
from User u left join fetch u.permissions where u.name = :name
// 或使用 JPA EntityGraph
@EntityGraph(attributePaths = {"permissions"})
User findByName(String name);
理解「Session 關閉 = 資料庫連線歸還」是關鍵。優先選擇 Open Session in View 或 精準載入策略,避免全域關閉延遲載入帶來的效能隱憂。