OpenSessionInView模式的起源:
OpenSessionInViewFilter是Spring提供的一個針對Hibernate的一個支援類,其主要意思是在發起一個頁面請求時開啟Hibernate的Session,一直保持這個Session,直到這個請求結束,具體是通過一個Filter來實現的。
由於Hibernate引入了Lazy Load特性,使得脫離Hibernate的Session周期的對象如果再想通過getter方法取到其關聯對象的值,Hibernate會拋出一個 LazyLoad的Exception。所以為瞭解決這個問題,Spring引入了這個Filter,使得Hibernate的Session的生命週期變長。
一個簡單的例子。
Java代碼
- public void doFilter(ServletRequest request, ServletResponse response,
- FilterChain filterChain) throws IOException, ServletException {
- try{
-
- Session session=HibernateSessionFactoryUtils.getSession();
- request.setAttribute(HIBERNATE_SESSIN_KEY, session);
- log.debug("用戶端請求開始,Hibernate Session已開啟.........");
- filterChain.doFilter(request, response);
- }finally {
- Object obj=request.getAttribute(HIBERNATE_SESSIN_KEY);
- if(obj!=null&&obj instanceof Session){
- Session session=(Session)obj;
- session.close();
- log.debug("用戶端請求結束,Hibernate Session已關閉.........");
- }else{
- log.error("用戶端請求結束,Hibernate Session未發現,請檢查代碼....");
- }
- }
- }
缺點:使用了OpenSessionInView 模式後造成了記憶體和資料庫連接問題
由於使用了OpenSessionInView 模式,Session的生命週期變得非常長。雖然解決了Lazy Load的問題,但是帶來的問題就是Hibernate的一級緩衝,也就是Session層級的緩衝的生命週期會變得非常長,那麼如果你在你的 Service層做大批量的資料操作時,其實這些資料會在緩衝中保留一份,這是非常耗費記憶體的。還有一個資料庫連接的問題,存在的原因在於由於資料庫的 Connection是和Session綁在一起的,所以,Connection也會得不到及時的釋放。因而當系統出現業務非常繁忙,而計算量又非常大的時候,往往資料連線池的串連數會不夠。這個問題我至今非常頭痛,因為有很多客戶對資料連線池的數量會有限制,不會給你無限制的增加下去。
在本地開發測試的時候沒出現問題,但試想下如果流程中的某一步被阻塞的話,那在這期間connection就一直被佔用而不釋放。最有可能被阻塞的就是在寫Jsp這步,一方面可能是頁面內容大,response.write的時間長,另一方面可能是網速慢,伺服器與使用者間傳輸時間久。當大量這樣的情況出現時,就有串連池串連不足,造成頁面假死現象。
解決方案:
1,使用OpenSessionInView Interceptor來代替這個Filter
2,使用Hibernate.initialize()方法初始會消極式載入的對象