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

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

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

    空間站

    北極心空

      BlogJava :: 首頁 :: 聯系 :: 聚合  :: 管理
      15 Posts :: 393 Stories :: 160 Comments :: 0 Trackbacks

    在沒有使用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. "openSessionInViewInterceptor"
    2. class="org.springframework.orm.hibernate3.support.OpenSessionInViewInterceptor">
    3. "sessionFactory">
    4. "sessionFactory"/>
    5.  
    6. "urlMapping"
    7. class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
    8. "interceptors">
    9. "openSessionInViewInterceptor"/>
    10.  
    11. "mappings">
    12. ...
    13.  
    14. ...
    OpenSessionInViewFilter配置
    1. ...
    2. hibernateFilter
    3. org.springframework.orm.hibernate3.support.OpenSessionInViewFilter
    4. ...
    5. hibernateFilter
    6. *.do
    7. ...

    很多人在使用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);
      }

               關于綁定session的方式,通過看spring里TransactionSynchronizationManager的實現,發現:它維護一個java.lang.ThreadLocal類型的resources,resources負責持有線程局部變量,這里resources持有的是一個HashMap,通過TransactionSynchronizationManager.bindResource()方法在map里綁定和線程相關的所有變量到他們的標識上,包括如上所述的綁定在sessionFactory上的線程局部session。sessionHolder只不過是存放可以hold一個session并可以和transtaction同步的容器。可以看到OpenSessionInViewFilter在getSession的時候,會把獲取回來的session的flush mode 設為FlushMode.NEVER。然后把該sessionFactory綁定到TransactionSynchronizationManager,使request的整個過程都使用同一個session,在請求過后再接除該sessionFactory的綁定,最后closeSessionIfNecessary根據該session是否已和transaction綁定來決定是否關閉session。綁定以后,就可以防止每次不會新開一個Session呢?看看HibernateDaoSupport的情況:

         1.  public final void setSessionFactory(SessionFactory sessionFactory) {    
    2. this.hibernateTemplate = new HibernateTemplate(sessionFactory);
    3. }
    4. protected final HibernateTemplate getHibernateTemplate() {
    5. return hibernateTemplate;
    6. }

            我們的DAO將使用這個template進行操作.

    public abstract class BaseHibernateObjectDao extends HibernateDaoSupport
    implements BaseObjectDao {
         protected BaseEntityObject getByClassId(final long id) {
                    BaseEntityObject obj =(BaseEntityObject) getHibernateTemplate().execute(new HibernateCallback() {
                            public Object doInHibernate(Session session) throws HibernateException {
                                        return session.get(getPersistentClass(),new Long(id));
                            }
                    });
                    return obj;
          }
         public void save(BaseEntityObject entity) {
                      getHibernateTemplate().saveOrUpdate(entity);
         }

        public void remove(BaseEntityObject entity) {
                  try {
                         getHibernateTemplate().delete(entity);
                  } catch (Exception e) {
                          throw new FlexEnterpriseDataAccessException(e);
                 }
         }

          public void refresh(final BaseEntityObject entity) {
                   getHibernateTemplate().execute(new HibernateCallback() {
                              public Object doInHibernate(Session session) throws HibernateException {
                                          session.refresh(entity);
                                          return null;
                              }
                   });
          }

         public void replicate(final Object entity) {
                    getHibernateTemplate().execute(new HibernateCallback() {
                              public Object doInHibernate(Session session)throws HibernateException {
                                          session.replicate(entity,ReplicationMode.OVERWRITE);
                                          return null;
                   }
                    });
          }
    }

            而HibernateTemplate試圖每次在execute之前去獲得Session,執行完就力爭關閉Session

      1. public Object execute(HibernateCallback action) throws DataAccessException {  
    2.    Session session = (!this.allowCreate ?  
    3.          SessionFactoryUtils.getSession(getSessionFactory(),
    4. false) :  
    5.          SessionFactoryUtils.getSession(getSessionFactory(),
    6. getEntityInterceptor(),
    7. getJdbcExceptionTranslator()));  
    8.     boolean existingTransaction =
    9. TransactionSynchronizationManager.hasResource(getSessionFactory());  
    10.    if (!existingTransaction && getFlushMode() == FLUSH_NEVER) {  
    11.          session.setFlushMode(FlushMode.NEVER);  
    12.    }  
    13.    try {  
    14.          Object result = action.doInHibernate(session);  
    15.          flushIfNecessary(session, existingTransaction);  
    16.          return result;  
    17.    }  
    18.    catch (HibernateException ex) {  
    19.          throw convertHibernateAccessException(ex);  
    20.    }  
    21.    finally {  
    22.          SessionFactoryUtils.closeSessionIfNecessary(
    23. session, getSessionFactory());  
    24.    }
    25. }

          而這個SessionFactoryUtils能否得到當前的session以及closeSessionIfNecessary是否真正關閉session,端取決于這個session是否用sessionHolder和這個sessionFactory在我們最開始提到的TransactionSynchronizationManager綁定。

         public static void closeSessionIfNecessary(Session session, SessionFactory sessionFactory)

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

        在這個過程中,若HibernateTemplate 發現自當前session有不是readOnly的transaction,就會獲取到FlushMode.AUTO Session,使方法擁有寫權限。也即是,如果有不是readOnly的transaction就可以由Flush.NEVER轉為Flush.AUTO,擁有insert,update,delete操作權限,如果沒有transaction,并且沒有另外人為地設flush model的話,則doFilter的整個過程都是Flush.NEVER。所以受transaction保護的方法有寫權限,沒受保護的則沒有。

    1. 可能的解決方式有:
      1、將singleSession設為false,這樣只要改web.xml,缺點是Hibernate Session的Instance可能會大增,使用的JDBC Connection量也會大增,如果Connection Pool的maxPoolSize設得太小,很容易就出問題。
      2、在控制器中自行管理Session的FlushMode,麻煩的是每個有Modify的Method都要多幾行程式。
            session.setFlushMode(FlushMode.AUTO);
            session.update(user);
            session.flush();
      3、Extend OpenSessionInViewFilter,Override protected Session getSession(SessionFactory sessionFactory),將FlushMode直接改為Auto。
      4、讓方法受Spring的事務控制。這就是常使用的方法:

    采用spring的事務聲明,使方法受transaction控制

    1.   class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"
                abstract="true">
             
             
             
                 
                      PROPAGATION_REQUIRED,readOnly
                      PROPAGATION_REQUIRED,readOnly
                      PROPAGATION_REQUIRED,readOnly
                      PROPAGATION_REQUIRED
                      PROPAGATION_REQUIRED
                      PROPAGATION_REQUIRED
                      PROPAGATION_REQUIRED
                 

             

         

    2.    
             
                 
             

         
       

    對于上例,則以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看起來還不錯,其實副作用不少??椿厣厦鍻penSessionInViewFilter的doFilterInternal方法代碼,這個方法實際上是被父類的doFilter調用的,因此,我們可以大約了解的OpenSessionInViewFilter調用流程: request(請求)->open session并開始transaction->controller->View(Jsp)->結束transaction并close session.

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

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

    另外:這樣會產生一點危險性,畢竟把數據庫訪問的環境放到了表現層。(用VO)

    posted on 2008-09-24 12:47 蘆葦 閱讀(1416) 評論(1)  編輯  收藏 所屬分類: SpringHibernate

    Feedback

    # re: [轉貼]OpenSessionInView與Hibernate事務處理機制 2013-07-05 15:54 stephenr
    不采用Open Session In View,那Hibernate的lazy加載怎么使用呢?  回復  更多評論
      

    主站蜘蛛池模板: 免费人成大片在线观看播放电影| 男人天堂免费视频| 亚洲精品国产精品乱码不卡| 中文字幕无码一区二区免费| 亚洲人成影院午夜网站| 亚洲免费在线观看| 永久免费视频网站在线观看| 国产亚洲视频在线观看网址| 亚洲成AV人片在线播放无码| 日韩精品无码人妻免费视频| 久久午夜夜伦鲁鲁片免费无码| 亚洲人成网站在线播放2019| 久久被窝电影亚洲爽爽爽| AV免费网址在线观看| 国产做国产爱免费视频| 中文字幕在线观看亚洲视频| 永久亚洲成a人片777777| 成全高清视频免费观看| 99久久成人国产精品免费| 亚洲午夜无码毛片av久久京东热| 亚洲欧洲日产国码无码网站| 成人免费一区二区三区在线观看| 成人免费ā片在线观看| 亚洲人片在线观看天堂无码| 久久久久亚洲精品日久生情| 亚洲国产成人久久综合一区77| 国产在线观看片a免费观看| 美女网站在线观看视频免费的| 亚洲精品无码专区久久| 激情内射亚洲一区二区三区| 国产亚洲人成A在线V网站 | 成人免费a级毛片无码网站入口 | 亚洲一区二区三区高清视频| 亚洲综合色区在线观看| 成人毛片视频免费网站观看| 91短视频在线免费观看| a级成人免费毛片完整版| 四虎影视久久久免费| 亚洲精品美女久久7777777| 亚洲天堂一区二区三区四区| 亚洲va久久久噜噜噜久久|