e代劍客——溫柔一刀

          生活就像海洋,只有意志堅強的人,才能到達彼岸

             :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理 ::
            76 隨筆 :: 7 文章 :: 215 評論 :: 0 Trackbacks
          Spring+Hibernate中OpenSessionInView模式運用 ?中會在Update Domain Object時遇到
          org.springframework.dao.InvalidDataAccessApiUsageException:?Write?operations?are?not?allowed?in?read-only?mode?(FlushMode.NEVER)?-?turn?your?Session?into?FlushMode.AUTO?or?remove?'readOnly'?marker?from?transaction?definition
          異常問題,這個Exception在尚未進入DAO時就會遇到,是一個會發生在Modify Domain Object時的問題。

          可能的解決方式有:
          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的事務控制。

          下面著重解說第4種方式:

          OpenSessionInViewFilter里的幾個方法:

          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); ?
          ??}
          ?
          }
          ?

          protected?Session?getSession(SessionFactory?sessionFactory)?
          throws?DataAccessResourceFailureException?{?
           Session?session?
          =?SessionFactoryUtils.getSession(sessionFactory,?true);?
           session.setFlushMode(FlushMode.NEVER);?
           
          return?session;?
          }
          ?
          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,使方法擁有寫權限:

          public?static?void?closeSessionIfNecessary(Session?session,?SessionFactory?sessionFactory)??????throws?CleanupFailureDataAccessException?{?
          ????
          if?(session?==?null?||?TransactionSynchronizationManager.hasResource(sessionFactory)){?
          ??????
          return;????
          }
          ?
          ????logger.debug(
          "Closing?Hibernate?session");?
          ????
          try?{?
          ??????session.close();?
          ????}
          ?
          ????
          catch?(JDBCException?ex)?{?
          ??????

          ?????throw?new?CleanupFailureDataAccessException("Could?not?close?Hibernate?session",?ex.getSQLException());?
          ????}
          ????catch?(HibernateException?ex)?{?
          ??????
          throw?new?CleanupFailureDataAccessException("Could?not?close?Hibernate?session",?ex);?
          ????}
          ?
          }
          ?

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

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

          <bean?id="manager"?class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
          ????????
          <property?name="proxyInterfaces">
          ????????????
          <list>
          ????????????????
          <value>com.zhupan.service.IManager</value>
          ????????????
          </list>
          ????????
          </property>
          ????????
          <property?name="transactionManager">
          ????????????
          <ref?bean="transactionManager"?/>
          ????????
          </property>
          ????????
          <property?name="target">
          ????????????
          <ref?local="managerTarget"?/>
          ????????
          </property>
          ????????
          <property?name="transactionAttributes">
          ????????????
          <props>????????????????????????????
          ????????????????
          <prop?key="*Insert">PROPAGATION_REQUIRED</prop>
          ????????????????
          <prop?key="*Update">PROPAGATION_REQUIRED</prop>
          ????????????????
          <prop?key="*Get*">PROPAGATION_REQUIRED,readOnly</prop>????
          ????????????????
          <prop?key="*List*">PROPAGATION_REQUIRED,readOnly</prop>????????????
          ????????????
          </props>
          ????????
          </property>
          ????
          </bean>

          對于上面的,以Insert,Update結尾的方法擁有可寫的事務,如果某個方法,如方法名為savaSort(),則沒有寫權限,這時若此方法內有insert,update,delete操作的話,則需要手動設置flush model為Flush.AUTO,如:

          session.setFlushMode(FlushMode.AUTO);?
          ??session.update(user);?
          ??session.flush();?

          posted on 2006-10-15 15:04 溫柔一刀 閱讀(2421) 評論(2)  編輯  收藏 所屬分類: 開源框架

          評論

          # re: 使用OpenSessionInView模式時的一個異常問題解決方法 2006-10-18 15:18 123bingbing
          增開7群,號碼 30440732
          8群 30756649
          9群 30178567
          10群 28694497

          我們的qq群:15096318 學習程序的都可以來
            回復  更多評論
            

          # re: 使用OpenSessionInView模式時的一個異常問題解決方法 2006-10-18 15:43 人上車
          @123bingbing
          這也可以打廣告啊?  回復  更多評論
            

          聯系偶 zhupanjava@gmail.com 溫柔一刀
          主站蜘蛛池模板: 满洲里市| 安康市| 阿瓦提县| 涞源县| 若尔盖县| 宜良县| 溧水县| 高唐县| 连城县| 上林县| 海丰县| 茂名市| 南丹县| 沂源县| 含山县| 健康| 贡觉县| 宜宾市| 郸城县| 闻喜县| 白水县| 广汉市| 莲花县| 广河县| 新安县| 肥乡县| 石门县| 庆城县| 西乌珠穆沁旗| 江口县| 靖远县| 宁津县| 乌兰县| 霸州市| 天台县| 七台河市| 如东县| 正镶白旗| 霍州市| 武乡县| 合肥市|