在使用spring+hibernate時,我們對實體的一對多,多對一和多對多的關聯實體進行獲取值的時候通常會使用懶加載的方式。這樣做的好處就是在我們需要關聯對象的屬性的時候,再去查詢數據庫,以至於我們不用一次查詢很多的數據出來。
這樣做經常會遇到一個異常:could not initialize proxy - no Session,本文就對此異常做各種處理方式的總結,結合實際需求去排除錯誤。
具體原因:使用懶加載方式,第一次獲取主體對象後session已經關閉了,所以再去查詢關聯對象的屬性時,沒有session可以使用。
解決辦法:
1. 使用fetch = FetchType.EAGER,即不使用懶加載,這樣一次性就加載所有的屬性,包括主體,關聯實體。
好處:避免了懶加載session不存在。
壞處:丟失了懶加載的特性,一次加載數據過多對於程序效率有所影響。
2. 手動的控制session的開關。即自己打開一個session,並在使用完成以後手動的顯示關閉該session。
Session session = sessionFactory.openSession(); // 通過session去查詢對應的實體 User user = session.find(id); // 獲取關聯對象 List<Role> roles = user.getRoles(); // 使用關聯對象 for(Role role : roles) { System.out.println(role.getName()); }
好處:使用懶加載特性,需要時再獲取。
壞處:需要手動的去控制session的開關。
應用場景:如spring容器啓動時,需要去獲取某對象關聯的屬性。或者Junit單元測試時。
3. 增加openSessionInView Filter,通過該filter來幫助實現session的開關控制。
<filter> <filter-name>openSessionInView</filter-name> <filter-class>org.springframework.orm.hibernate4.support.OpenSessionInViewFilter</filter-class> </filter> <filter-mapping> <filter-name>openSessionInView</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
好處:我們不需要手動的去控制session的開關。
壞處:對於像沒有使用web容器,或者web容器並未啓動,亦或者根本就沒有發送請求即沒有通過該Filter,則無法完成該功能。這種情況只有使用解決方法二。
應用場景:web應用,有請求發生並且請求被Filter攔截的情況