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

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

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

    空間站

    北極心空

      BlogJava :: 首頁 :: 聯(lián)系 :: 聚合  :: 管理
      15 Posts :: 393 Stories :: 160 Comments :: 0 Trackbacks

    在沒有使用Spring提供的Open Session In View情況下,因需要在service(or Dao)層里把session關(guān)閉,所以lazy loading true的話,要在應(yīng)用層內(nèi)把關(guān)系集合都初始化,如 company.getEmployees(),否則Hibernatesession already closed Exception;    Open Session In View提供了一種簡便的方法,較好地解決了lazy loading問題.

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

        Open Session In Viewrequestsession綁定到當(dāng)前thread期間一直保持hibernate sessionopen狀態(tài),使sessionrequest的整個期間都可以使用,如在View層里PO也可以lazy loading數(shù)據(jù),如 ${ company.employees }。當(dāng)View 層邏輯完成后,才會通過FilterdoFilter方法或InterceptorpostHandle方法自動關(guān)閉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);
      }

               關(guān)于綁定session的方式,通過看spring里TransactionSynchronizationManager的實現(xiàn),發(fā)現(xiàn):它維護一個java.lang.ThreadLocal類型的resources,resources負(fù)責(zé)持有線程局部變量,這里resources持有的是一個HashMap,通過TransactionSynchronizationManager.bindResource()方法在map里綁定和線程相關(guān)的所有變量到他們的標(biāo)識上,包括如上所述的綁定在sessionFactory上的線程局部session。sessionHolder只不過是存放可以hold一個session并可以和transtaction同步的容器。可以看到OpenSessionInViewFilter在getSession的時候,會把獲取回來的session的flush mode 設(shè)為FlushMode.NEVER。然后把該sessionFactory綁定到TransactionSynchronizationManager,使request的整個過程都使用同一個session,在請求過后再接除該sessionFactory的綁定,最后closeSessionIfNecessary根據(jù)該session是否已和transaction綁定來決定是否關(guān)閉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,執(zhí)行完就力爭關(guān)閉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能否得到當(dāng)前的session以及closeSessionIfNecessary是否真正關(guān)閉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 發(fā)現(xiàn)自當(dāng)前session有不是readOnly的transaction,就會獲取到FlushMode.AUTO Session,使方法擁有寫權(quán)限。也即是,如果有不是readOnly的transaction就可以由Flush.NEVER轉(zhuǎn)為Flush.AUTO,擁有insert,update,delete操作權(quán)限,如果沒有transaction,并且沒有另外人為地設(shè)flush model的話,則doFilter的整個過程都是Flush.NEVER。所以受transaction保護的方法有寫權(quán)限,沒受保護的則沒有。

    1. 可能的解決方式有:
      1、將singleSession設(shè)為false,這樣只要改web.xml,缺點是Hibernate Session的Instance可能會大增,使用的JDBC Connection量也會大增,如果Connection Pool的maxPoolSize設(shè)得太小,很容易就出問題。
      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的事務(wù)控制。這就是常使用的方法:

    采用spring的事務(wù)聲明,使方法受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開頭的方法擁有可寫的事務(wù),如果當(dāng)前有某個方法,如命名為importExcel(),則因沒有transaction而沒有寫權(quán)限,這時若方法內(nèi)有insert,update,delete操作的話,則需要手動設(shè)置flush model為Flush.AUTO,如

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

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

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

    Open Session In View是個雙刃劍,放在公網(wǎng)上內(nèi)容多流量大的網(wǎng)站請慎用。

    另外:這樣會產(chǎn)生一點危險性,畢竟把數(shù)據(jù)庫訪問的環(huán)境放到了表現(xiàn)層。(用VO)

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

    Feedback

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

    主站蜘蛛池模板: 你懂的免费在线观看网站| 亚洲 小说区 图片区 都市| 国产日韩AV免费无码一区二区三区 | 久久www免费人成看片| 人妻巨大乳hd免费看| 亚洲综合久久精品无码色欲| 亚洲国产精品久久久久网站| 中文亚洲AV片不卡在线观看| 免费涩涩在线视频网| 免费三级毛片电影片| 久久永久免费人妻精品下载| a级午夜毛片免费一区二区| 免费无毒a网站在线观看| 亚洲AV综合色区无码一二三区| 亚洲狠狠狠一区二区三区| 午夜亚洲www湿好大| 亚洲无人区午夜福利码高清完整版| 亚洲?V乱码久久精品蜜桃| 国产特级淫片免费看| 精品剧情v国产在免费线观看| 无码乱肉视频免费大全合集| 99re免费在线视频| 久久国产乱子伦精品免费一| 久久九九免费高清视频| www成人免费观看网站| 一级特黄录像视频免费| 无人视频在线观看免费播放影院| 综合一区自拍亚洲综合图区| 亚洲aⅴ天堂av天堂无码麻豆 | 精品女同一区二区三区免费站| 色欲色香天天天综合网站免费| 久久精品电影免费动漫| 久久精品视频免费看| 国产成人无码区免费网站| 精品无码一级毛片免费视频观看| 亚洲精品视频免费| 久久精品成人免费国产片小草| 九九精品成人免费国产片| 久久国产精品国产自线拍免费| 97在线免费视频| 无码国产精品一区二区免费16|