1. 程式人生 > >hibernate的延遲載入及其與session關閉的矛盾

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的程式碼註釋掉。