分析Hibernate:could not initialize proxy - no Session
異常:
org.hibernate.LazyInitializationException: could not initialize proxy - no Session
在做一個專案的時候遇到了這個問題,大概的意思是不能 初始化,session 關閉了的,於是就想到可能是session關閉了 而程式某個地方還在從資料庫中讀取資料
於是就上網百度了一下, 說的是在用多對一或者是多對多的時候懶載入的問題
下面先看下 hibernate裡lazy 的內容(上面出錯的解決辦法,我會在下面給出)
lazy,延遲載入
Lazy的有效期:只有在session開啟的時候才有效;session關閉後lazy就沒效了。
lazy策略可以用在:
<class>
標籤上:可以取值true/false<property>
標籤上,可以取值true/false,這個特性需要類增強<set>/<list>
等集合上,可以取值為true/false/extra<one-to-one>/<many-to-one>
等標籤上,可以取值false/proxy/no-proxy
1 get和load的區別:
get不支援延遲載入,而load支援。
當查詢特定的資料庫中不存在的資料時,get會返回null,而load則丟擲異常。
2 類(Class)的延遲載入:
設定標籤中的lazy=”true”,或是保持預設(即不配置lazy屬性)
如果lazy的屬性值為true,那麼在使用load方法載入資料時,只有確實用到資料的時候才會發出sql語句;這樣有可能減少系統的開銷。
//不會發出查詢sql
System.out.println(“group id=” + group.getId());
這裡有一個問題,為什麼載入主鍵的時候不需要發出sql語句。
3 集合(collection)的延遲載入:可以取值true,false,extra
保持集合上的lazy的預設值,此時的效果和lazy=”extra”是基本一樣的。
- 設定集合上的lazy=extra,此時的效果和lazy屬性的預設值是基本一樣的。但是推薦使用這個屬性值,因為在統計時這種情況顯得比較智慧。當然延遲是有效果的。
設定集合上的lazy=false
true:預設取值,它的意思是隻有在呼叫這個集合獲取裡面的元素物件時,才發出查詢語句,載入其集合元素的資料
false:取消懶載入特性,即在載入物件的同時,就發出第二條查詢語句載入其關聯集合的資料
extra:一種比較聰明的懶載入策略,即呼叫集合的size/contains等方法的時候,hibernate
並不會去載入整個集合的資料,而是發出一條聰明的SQL語句,以便獲得需要的值,只有在真正需要用到這些集合元素物件資料的時候,才去發出查詢語句載入所有物件的資料
4 Hibernate單端關聯懶載入策略:即在/標籤上可以配置
懶載入策略。可以取值為:false/proxy/no-proxy
false:取消懶載入策略,即在載入物件的同時,發出查詢語句,載入其關聯物件
proxy:這是hibernate對單端關聯的預設懶載入策略,即只有在呼叫到其關聯物件的方法的時候才真正發出查詢語句查詢其物件資料,其關聯物件是代理類
no-proxy:這種懶載入特性需要對類進行增強,使用no-proxy,其關聯物件不是代理類
看了上面的lazy的內容之後 你可能自己就有了解決辦法 (我的專案問題就是默認了lazy為true 然而我在後面有用到了懶載入)
出現問題的原因:
在Hibernate中,
<many-to-one name="teacher" class="Teacher" column="T_ID" lazy="false" ></many-to-one>
2、使用OpenSessionInViewFilter。這種方法是將session交給servlet filter來管理,每當一個請求來之後就會開
啟一個session,只有當響應結束後才會關閉。如下:
<filter-name>hibernateFilter</filter-name>
<filter-class> org.springframework.orm.hibernate3.support.OpenSessionInViewFilter </filter-class>
</filter
<filter-mapping>
<filter-name>hibernateFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
上面的配置檔案時在web.xml中配置的。
3、將hibernate的抓起策略改為join。也就是是left join fetch或inner join fetch語法。就是在<many-to-one../>
中配
置lazy=”false” fetch=”join”即可。如:
<many-to-one name="teacher" class="Teacher" column="T_ID" lazy="false" fetch="join" ></many-to-one>