延遲加載就是並不是在讀取的時候就把數據加載進來,而是等到使用時再加載。
那么Hibernate是怎么知道用戶在什么時候使用數據了呢?又是如何加載數據呢?
其實很簡單,它使用了代理機制。返回給用戶的並不是實體本身,而是實體對象的代理。代理對象在用戶調用getter方法時就會去數據庫加載數據。
但加載數據就需要數據庫連接。而當我們把會話關閉時,數據庫連接就同時關閉了。這種情況就叫做未初始化的關系。
延遲加載與session關閉的矛盾一般可以這樣處理:
1)、關閉延遲加載特性。 操作起來比較簡單,因為hibernate的延遲加載特性是在hbm配置里面可控制的。默認lazy="true",改為lazy="false"就可以了。 但是使用這個解決辦法帶來的隱患是十分大的。 首先,出現no session or session was closed就證明了您已經在使用外鍵關聯表,如果去掉延遲加載的話,則表示每次查詢的開銷都會變得十分的大,如果關聯表越多,后果也可以想象得到。所以不建議使用這個方法解決。
2)、在session關閉之前把我們想要查詢的數據先獲取了。 首先需要了解一下session什么時候關閉,也就是它的生命周期。通常情況下hibernate會在查詢數據關閉session,而使用getHibernateTemplate().get方法查詢后會延遲關閉的時間。會在事務結束后才關閉。 使用攔截器(Interceptor)或過濾器(Filter)控制session。 spring為解決hibernate這一特性提供的解決方案,可以有效的控制session生命周期。
因為還沒有講到Spring,課堂上用過濾器(Filter)來控制session。
首先建個類OpenSessionInViewFilter繼承Filter,重寫doFilter方法,在try,finally中編寫session的獲得和關閉。實例代碼如下:
public void doFilter( ServletRequest arg0, ServletResponse arg1, FilterChain chain) throws IOException, ServletException { try { HibUtil.getSession(); chain.doFilter(arg0, arg1); } finally { HibUtil.closeSession(); } }
然后在web.xml配置文件中增加相關配置,例如:
<filter> <filter-name>OpenSessionInViewFilter</filter-name> <filter-class> tarena.util.OpenSessionInViewFilter </filter-class> </filter> <filter-mapping> <filter-name>OpenSessionInViewFilter</filter-name> <url-pattern>*.action</url-pattern> </filter-mapping>
最后要記得修改service層事務處理的代碼,把關閉session的代碼注釋掉。