hibernate的延遲載入及其與session關閉的矛盾
那麼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的程式碼註釋掉。