<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    lqxue

    常用鏈接

    統計

    book

    tools

    最新評論

    Open Session In View

    http://www.54bk.com/user1/2690/archives/2006/2006122116259.html

    Open Session In View解決session.close問題
    ssuupv 發表于 2006-12-21 16:25:00
      在沒有使用Spring提供的Open Session In View情況下,因需要在service(or Dao)層里把session關閉,所以lazy loading true的話,要在應用層內把關系集合都初始化,如 company.getEmployees(),否則Hibernatesession already closed Exception;    Open Session In View提供了一種簡便的方法,較好地解決了lazy loading問題.

        它有兩種配置方式OpenSessionInViewInterceptorOpenSessionInViewFilter(具體參看SpringSide),功能相同,只是一個在web.xml配置,另一個在application.xml配置而已。

        Open Session In Viewrequestsession綁定到當前thread期間一直保持hibernate sessionopen狀態,使sessionrequest的整個期間都可以使用,如在View層里PO也可以lazy loading數據,如 ${ company.employees }。當View 層邏輯完成后,才會通過FilterdoFilter方法或InterceptorpostHandle方法自動關閉session

                            
    OpenSessionInViewInterceptor配置
    1. <beans>
    2. <bean name="openSessionInViewInterceptor"
    3. class="org.springframework.orm.hibernate3.support.OpenSessionInViewInterceptor">
    4. <property name="sessionFactory">
    5. <ref bean="sessionFactory"/>
    6. </property>
    7. </bean>
    8. <bean id="urlMapping"
    9. class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
    10. <property name="interceptors">
    11. <list>
    12. <ref bean="openSessionInViewInterceptor"/>
    13. </list>
    14. </property>
    15. <property name="mappings">
    16. ...
    17. </property>
    18. </bean>
    19. ...
    20. </beans>
                            
    OpenSessionInViewFilter配置
    1. <web-app>
    2. ...
    3. <filter>
    4. <filter-name>hibernateFilter</filter-name>
    5. <filter-class>
    6. org.springframework.orm.hibernate3.support.OpenSessionInViewFilter
    7. </filter-class>
    8. <!-- singleSession默認為true,若設為false則等于沒用OpenSessionInView -->
    9. <init-param>
    10. <param-name>singleSession</param-name>
    11. <param-value>true</param-value>
    12. </init-param>
    13. </filter>
    14. ...
    15. <filter-mapping>
    16. <filter-name>hibernateFilter</filter-name>
    17. <url-pattern>*.do</url-pattern>
    18. </filter-mapping>
    19. ...
    20. </web-app>

    很多人在使用OpenSessionInView過程中提及一個錯誤:

                            
    1. org.springframework.dao.InvalidDataAccessApiUsageException: Write operations
    2. are not allowed in read-only mode (FlushMode.NEVER) - turn your Session into
    3. FlushMode.AUTO or remove 'readOnly' marker from transaction definition

    看看OpenSessionInViewFilter里的幾個方法

                            
    1. protected void doFilterInternal(HttpServletRequest request,
      HttpServletResponse response,FilterChain filterChain)
      throws ServletException, IOException {
       SessionFactory sessionFactory = lookupSessionFactory();
       logger.debug("Opening Hibernate Session in OpenSessionInViewFilter");
       Session session = getSession(sessionFactory);
       TransactionSynchronizationManager.bindResource(
        sessionFactory, new SessionHolder(session));
       try {
        filterChain.doFilter(request, response);
       }
       finally {
       TransactionSynchronizationManager.unbindResource(sessionFactory);
       logger.debug("Closing Hibernate Session in OpenSessionInViewFilter");
       closeSession(session, sessionFactory);
       }
      }





       
    2. protected Session getSession(SessionFactory sessionFactory)
      throws DataAccessResourceFailureException {
       Session session = SessionFactoryUtils.getSession(sessionFactory, true);
       session.setFlushMode(FlushMode.NEVER);
       return session;
      }

    3. protected
      void closeSession(Session session, SessionFactory sessionFactory)
      throws CleanupFailureDataAccessException {
       SessionFactoryUtils.closeSessionIfNecessary(session, sessionFactory);
      }

         可以看到OpenSessionInViewFilter在getSession的時候,會把獲取回來的session的flush mode 設為FlushMode.NEVER。然后把該sessionFactory綁定到TransactionSynchronizationManager,使request的整個過程都使用同一個session,在請求過后再接除該sessionFactory的綁定,最后closeSessionIfNecessary根據該session是否已和transaction綁定來決定是否關閉session。在這個過程中,若HibernateTemplate 發現自當前session有不是readOnly的transaction,就會獲取到FlushMode.AUTO Session,使方法擁有寫權限。

                            
    1. public static void closeSessionIfNecessary(Session session, SessionFactory sessionFactory)
    2. throws CleanupFailureDataAccessException {
    3. if (session == null ||
      TransactionSynchronizationManager.hasResource(sessionFactory)) {
    4. return;
    5. }
    6. logger.debug("Closing Hibernate session");
    7. try {
    8. session.close();
    9. }
    10. catch (JDBCException ex) {
    11. // SQLException underneath
    12. throw new CleanupFailureDataAccessException("Could not close Hibernate session", ex.getSQLException());
    13. }
    14. catch (HibernateException ex) {
    15. throw new CleanupFailureDataAccessException("Could not close Hibernate session", ex);
    16. }
    17. }

        也即是,如果有不是readOnly的transaction就可以由Flush.NEVER轉為Flush.AUTO,擁有insert,update,delete操作權限,如果沒有transaction,并且沒有另外人為地設flush model的話,則doFilter的整個過程都是Flush.NEVER。所以受transaction保護的方法有寫權限,沒受保護的則沒有。

                            
    采用spring的事務聲明,使方法受transaction控制
    1.   <bean id="baseTransaction"
      class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"
                abstract="true">
              <property name="transactionManager" ref="transactionManager"/>
              <property name="proxyTargetClass" value="true"/>
              <property name="transactionAttributes">
                  <props>
                      <prop key="get*">PROPAGATION_REQUIRED,readOnly</prop>
                      <prop key="find*">PROPAGATION_REQUIRED,readOnly</prop>
                      <prop key="load*">PROPAGATION_REQUIRED,readOnly</prop>
                      <prop key="save*">PROPAGATION_REQUIRED</prop>
                      <prop key="add*">PROPAGATION_REQUIRED</prop>
                      <prop key="update*">PROPAGATION_REQUIRED</prop>
                      <prop key="remove*">PROPAGATION_REQUIRED</prop>
                  </props>
              </property>
          </bean>

    2.     <bean id="userService" parent="baseTransaction">
              <property name="target">
                  <bean class="com.phopesoft.security.service.impl.UserServiceImpl"/>
              </property>
          </bean>

      對于上例,則以save,add,update,remove開頭的方法擁有可寫的事務,如果當前有某個方法,如命名為importExcel(),則因沒有transaction而沒有寫權限,這時若方法內有insert,update,delete操作的話,則需要手動設置flush model為Flush.AUTO,如

                                  
      1. session.setFlushMode(FlushMode.AUTO);
      2. session.save(user);
      3. session.flush();

           盡管Open Session In View看起來還不錯,其實副作用不少。看回上面OpenSessionInViewFilter的doFilterInternal方法代碼,這個方法實際上是被父類的doFilter調用的,因此,我們可以大約了解的OpenSessionInViewFilter調用流程: request(請求)->open session并開始transaction->controller->View(Jsp)->結束transaction并close session.

           一切看起來很正確,尤其是在本地開發測試的時候沒出現問題,但試想下如果流程中的某一步被阻塞的話,那在這期間connection就一直被占用而不釋放。最有可能被阻塞的就是在寫Jsp這步,一方面可能是頁面內容大,response.write的時間長,另一方面可能是網速慢,服務器與用戶間傳輸時間久。當大量這樣的情況出現時,就有連接池連接不足,造成頁面假死現象。

      Open Session In View是個雙刃劍,放在公網上內容多流量大的網站請慎用。


      閱讀全文(302) | 回復(0) | 引用通告(638) | 編輯
       

      posted on 2007-04-03 08:58 lqx 閱讀(241) 評論(0)  編輯  收藏


      只有注冊用戶登錄后才能發表評論。


      網站導航:
       
      主站蜘蛛池模板: a级片免费观看视频| 亚洲AV成人一区二区三区观看| 理论片在线观看免费| 四虎影视免费在线| 亚洲国产激情在线一区| 国产精品久久久久免费a∨ | 成人a视频片在线观看免费| 亚洲性69影院在线观看| 亚欧色视频在线观看免费| 亚洲成在人线中文字幕| 成人免费一级毛片在线播放视频| 亚洲国产午夜精品理论片| 成人免费视频69| 亚洲人成网站18禁止| 在线免费观看韩国a视频| 国产成人+综合亚洲+天堂| 亚洲VA综合VA国产产VA中| eeuss草民免费| 亚洲电影一区二区三区| 中文字幕天天躁日日躁狠狠躁免费| 亚洲视频在线观看网站| 免费人成在线视频| 毛片亚洲AV无码精品国产午夜| 亚洲人AV永久一区二区三区久久| a在线视频免费观看| 亚洲美女人黄网成人女| 天天干在线免费视频| 一区二区三区视频免费| 亚洲第一精品在线视频| 在线免费视频一区| v片免费在线观看| 亚洲视频在线一区| 日本xxwwxxww在线视频免费| GOGOGO免费观看国语| 91亚洲导航深夜福利| 色www永久免费视频| 久久国产精品国产自线拍免费| 精品亚洲AV无码一区二区| 亚洲第一视频在线观看免费| 久久国产免费观看精品3| 国产亚洲精品美女|