今天在寫struts2 項目的時候,我一在jsp頁面(有其他struts2标簽,顯示無誤)中,一輸入struts2的<s:debug></s:debug>标簽,就出現了如下錯誤:(删掉這個标簽後又正常使用)
嚴重: Servlet.service() for servlet jsp threw exception
org.hibernate.LazyInitializationException: could not initialize proxy - no Session
at org.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializer.java:164)
at org.hibernate.proxy.AbstractLazyInitializer.getImplementation(AbstractLazyInitializer.java:285)
at org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer.invoke(JavassistLazyInitializer.java:185)
at com.chenruijia.ssh.entities.Department_$$_javassist_0.toString(Department_$$_javassist_0.java)
at java.lang.String.valueOf(String.java:2827)
at java.lang.StringBuffer.append(StringBuffer.java:219)
at freemarker.ext.beans.SimpleMethodModel.exec(SimpleMethodModel.java:130)
at freemarker.core.MethodCall._getAsTemplateModel(MethodCall.java:93)
at freemarker.core.Expression.getAsTemplateModel(Expression.java:89)
at freemarker.core.Expression.getStringValue(Expression.java:93)
at freemarker.core.StringBuiltins$StringBuiltIn._getAsTemplateModel(StringBuiltins.java:71)
......
我就很納悶了,一個struts2的标簽怎麼會影響到hibernate的session呢?
分析:
注意看上面的紅色标記出來的内容(此時發現學好英語真的很重要!),仔細看,大概的意思是懶加載的問題吧,
意思是在session(hibernate裡的session)關閉後使用employee對象的未加載變量,也就是說session已經關閉,然而該執行個體變量卻還沒有被初始化,就使用了該執行個體變量,導緻該異常。
于是,我專門隻查詢
這個異常的原因,看到了這篇文章 https://www.cnblogs.com/TTTTT/p/6682798.html(應該和我做的是同一個小項目),裡面提到:
由于employee是由hibernate進行加載的,可能hibernate本身是以load的方式将該執行個體變量得到。此時在employeeDao裡session擷取到的是的employee代理類對象,整個Session範圍内,應用程式沒有通路過employee對象,那麼employee代理類的執行個體一直不會被初始話。事務是作用在EmployeeService上,導緻
List<Employee> getAll( )方法調用之前擷取Session、開啟事務,這個方法結束之後送出事務、關閉session。session關閉後,在EmployeeAction擷取employee時是未初始化的employee代理類對象,未被初始化的代理類對象隻有OID其他屬性全為null,那麼放入request的Map裡的是未被初始化的employee代理類對象。一旦在action或者jsp裡要擷取employee代理類對象,必然會發生懶加載異常。同理,在jsp裡擷取employee的department時同樣存在懶加載的問題。
(關于hiberante的延遲加載,更詳細的在原作者的另一篇部落格裡:http://www.cnblogs.com/TTTTT/p/6682304.html)
解決辦法:
方法1.用openSessionInView 。
方法2.把這個類的延遲加載禁掉,lazy設為false。
方法3.迫切左外連接配接
但是,關鍵在于我已經使用了迫切左外連接配接(在前一個頁面顯示清單資訊的時候已經遇到過這樣的問題,在我的getList()方法中是使用了迫切左外連接配接:
//查詢所有的員工資訊
public List<Employee> getAll(){
//迫切左連接配接
String hql = "FROM Employee e LEFT OUTER JOIN FETCH e.department";
List<Employee> list = getSession().createQuery(hql).list();
return list;
}
然後我在希望去對應的修改頁面上時,我使用了get(id)這個方法,在加上<s:debug>标簽後才抛了這個異常。
//查詢單個員工資訊
public Employee get(Integer id){
return (Employee) getSession().get(Employee.class,id);
}
于是,我在employee.hbm.xml檔案中,嘗試将其懶加載關掉。
<!-- 映射單向 n-1 的關聯關系 -->
<many-to-one name="department" class="com.chenruijia.ssh.entities.Department" lazy="false">
<column name="DEPARTMENT_ID" />
</many-to-one>
個人分析:
确實,解決這種懶加載的問題确實是上面的三個方法,(對于方法2和3)老師推薦我們使用迫切左外連接配接而不是取消懶加載,但是如果需要根據不同的條件去寫方法,每個都用迫切左外連接配接未免太麻煩。我想,在學習過程中,不需要懶加載的情況下也可以直接關閉懶加載,而更加友善,當然,以後實際開發可以用第一種方法或者其他的方法會更加科學。
最後,雖然問題解決了,但是對于之前 “<s:debug>标簽就不行,删掉就好” 的問題,個人水準問題還是沒法解決,可能是<s:debug>内部的機制要求的吧!希望有大神可以指點一下。
結束和聲明
以上純屬個人觀點和體會
希望這篇文章能對你有所幫助!
歡迎大家來一起讨論分享幹貨,或者批評指正!
更加熱切盼望各路大神前輩給些指導和建議!
以後會不定期更新心得和總結,包括學習過程中各種異常和解決辦法等等。再見!