當持久層利用session的load()的方法去查詢數(shù)據(jù)時,返回的只是虛擬代理,此時并沒有真正的發(fā)送sql語句,如果在視圖上使用到查詢的數(shù)據(jù)時,此時sql語句才會真正發(fā)出,但這時候會話已經被關閉,無法在獲取到數(shù)據(jù)。又或者在一對多的關聯(lián)場景下,存在懶加載情況,也會出現(xiàn)延遲加載和會話關閉的矛盾。
一、利用Spring的OpenSessionInViewFilter過濾器延長會話的生命周期
web.xml中配置過濾器
<filter>
<filter-name>osiv</filter-name>
<filter-class>org.springframework.orm.hibernate5.support.OpenSessionInViewFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>osiv</filter-name>
<url-pattern>*.do</url-pattern>
</filter-mapping>
配置完過濾器后,session的生命周期就會延長直到視圖渲染完成后才結束session。
存在的問題:
在高并發(fā)的情況下、影響性能。因為這樣一來,每個從這個過濾器過的請求的session都要被延長生命周期,因為會話上綁定了數(shù)據(jù)庫連接。所以很有可能使數(shù)據(jù)庫連接被某些無用的session占用,導致真正需要連接的會話被阻塞。
二、利用Hibernate工具類的isInitialized方法來解決
以user為例,在控制代碼中,提前初始化視圖上需要用到的數(shù)據(jù):
/*
* 利用Hibernate工具類的isInitialized方法,判斷user是否被初始化
* 是的時候返回true,否則返回false
* 如果沒有被初始化則用Hibernate工具類的initialize將對象初始化
*/
if(!Hibernate.isInitialized(user)) {
Hibernate.initialize(user);
}
但是這樣的做法就需要我們去對代碼的邏輯做一些修改,并且使方法和hibernate有了一定的耦合。
三、自定義過濾器
和Spring的OpenSessionInViewFilter一樣,我們可以自己定義一個過濾器,來延長會話的生命周期。
拿到SpringIoC容器:
ServletContext sc = requset.getServletContext();
WebApplicationContext ctx =
WebApplicationContextUtils.getWebApplicationContext(sc);
從容器中取出Session并在chain.doFilter(request, response);前后分別開啟和關閉會話。這種做法和Spring的OpenSessionInViewFilter沒什么本質區(qū)別。