posts - 11,  comments - 28,  trackbacks - 0

          本文是在參閱了http://ivanl.javaeye.com/blog/24739基礎上完成的
          在看JPetStore的代碼時,發現它的分頁處理主要是通過返回PaginatedList對象來完成的。如:在CatalogService類中
          public?PaginatedList?getProductListByCategory(String?categoryId)?{?
          ????
          return?productDao.getProductListByCategory(categoryId);?
          ??}
          ?

          分頁是操作數據庫型系統常遇到的問題。分頁實現方法很多,但效率的差異就很大了。iBatis是通過什么方式來實現這個分頁的了。查看它的實現部分:
          ?
          返回的PaginatedList實際上是個接口,實現這個接口的是PaginatedDataList類的對象,查看PaginatedDataList類發現,每次翻頁的時候最后都會調用下面這段函數
          private?List?getList(int?idx,?int?localPageSize)?throws?SQLException?{?
          ????
          return?sqlMapExecutor.queryForList(statementName,?parameterObject,?(idx)?*?pageSize,?localPageSize);?
          ??}
          ?
          由于
          public?interface?SqlMapClient?extends?SqlMapExecutor,?SqlMapTransactionManager?{……}?

          所以實際的調用次序如下:
          SqlMapClientImpl.queryForPaginatedList->SqlMapSessionImpl.queryForPaginatedList?
          ->SqlMapExecutorDelegate.queryForPaginatedList->GeneralStatement.executeQueryForList?
          ->GeneralStatment.executeQueryWithCallback->GeneralStatment.executeQueryWithCallback?
          ->SqlExecutor.executeQuery->SqlExecutor.handleMultipleResults()->SqlExecutor.executeQuery->?handleResults?
          分頁處理的函數如下
          private?void?handleResults(RequestScope?request,?ResultSet?rs,?int?skipResults,?int?maxResults,?RowHandlerCallback?callback)?throws?SQLException?{?
          ????
          try?{?
          ??????request.setResultSet(rs);?
          ??????ResultMap?resultMap?
          =?request.getResultMap();?
          ??????
          if?(resultMap?!=?null)?{?
          ????????
          //?Skip?Results?
          ????????if?(rs.getType()?!=?ResultSet.TYPE_FORWARD_ONLY)?{?
          ??????????
          if?(skipResults?>?0)?{?
          ????????????rs.absolute(skipResults);?
          ??????????}
          ?
          ????????}
          ?else?{?
          ??????????
          for?(int?i?=?0;?i?<?skipResults;?i++)?{?
          ????????????
          if?(!rs.next())?{?
          ??????????????
          return;?
          ????????????}
          ?
          ??????????}
          ?
          ????????}
          ?
          ??
          ????????
          //?Get?Results?
          ????????int?resultsFetched?=?0;?
          ????????
          while?((maxResults?==?SqlExecutor.NO_MAXIMUM_RESULTS?||?resultsFetched?<?maxResults)?&&?rs.next())?{?
          ??????????Object[]?columnValues?
          =?resultMap.resolveSubMap(request,?rs).getResults(request,?rs);?
          ??????????callback.handleResultObject(request,?columnValues,?rs);?
          ??????????resultsFetched
          ++;?
          ????????}
          ?
          ??????}
          ?
          ????}
          ?finally?{?
          ??????request.setResultSet(
          null);?
          ????}
          ?
          ??}
          ?

          由此可見,iBatis的分頁主要依賴于jdbcdriver的如何實現以及是否支持rs.absolute(skipResults)。它并不是一個好的分頁方式。它先要取出所有的符合條件的記錄存入ResultSet對象,然后用absolute方法進行定位,來實現分頁。當記錄數較大(比如十萬條)時,整體的查詢速度將會變得很慢。
          所以分頁還是要考慮采用直接操作sql語句來完成。當然小批量的可以采用iBatis的分頁模式。一般分頁的sql語句與數據庫的具體實現有關
          mysql:?
          select?*?from?A?limit?startRow,endRow?
          oracle:?
          select?b.*?from?(select?a.*,rownum?as?linenum?from?(select?*?from?A)?a?where?rownum?<=?endRow)?b?where?linenum?>=?startRow?

          Hibernate的Oracle分頁采用的就是是拼湊RowNum的Sql語句來完成的。參考代碼如下:?
          ?
          ????????public?String?createOraclePagingSql(String?sql,?int?pageIndex,?int?pageSize){?
          ????????????
          int?m?=?pageIndex?*?pageSize;?
          ????????????
          int?n?=?m?+?pageSize;?
          ????????????
          return?"select?*?from?(?select?row_.*,?rownum?rownum_?from?(?"?+?sql?
          ????????????????????
          +?"?)?row_?where?rownum?<=?"?+?n??
          ????????????????????
          +?")?where?rownum_?>?"?+?m;?
          ????????}
          ?
          綜上,小批量(<2w)可以采用ibatis自帶的分頁類,大批量的還是直接操縱sql,當然也可以將這些sql自己進行封裝,或在包中封裝都可以。包封裝的示例代碼如下:
          一個封裝了分頁功能的Oracle Package
          create?or?replace?package?body?FMW_FY_HELPER?is
          PROCEDURE?GET_DATA(pi_sql?in?varchar,pi_whichpage?in?integer,pi_rownum?in?integer,
          po_cur_data?out?cur_DATA,po_allrownum?out?
          integer,pio_succeed?in?out?integer)
          as?
          v_cur_data?cur_DATA;
          v_cur_temp?cur_TEMP;
          v_temp?
          integer;
          v_sql?
          varchar(5000);
          v_temp1?
          integer;
          v_temp2?
          integer;
          begin
          pio_succeed?:
          =?1;
          v_sql?:
          =?'select?count(''a'')?from?(?'?||?pi_sql?||?')';
          execute?immediate?v_sql?into?v_temp;

          po_allrownum:
          =ceil(v_temp/pi_rownum);

          v_sql?:
          =?'';
          v_temp?:
          =pi_whichpage*pi_rownum?+?1;
          v_temp1:
          =(pi_whichpage-1)*pi_rownum?+?1;
          v_temp2:
          =pi_whichpage*pi_rownum;
          v_sql:
          =?'select?*?from?(select?rownum?as?rn,t.*?from?('?||?pi_sql?||')?t?where?rownum<'?||?to_char(v_temp)?||?')??where?rn?between?'?||?to_char(v_temp1)?||?'?and?'?||?to_char(v_temp2);
          open?v_cur_data?for?v_sql;
          if?v_cur_data?%notfound
          then
          pio_succeed:
          =-1;
          return;
          end?if;
          po_cur_DATA?:
          =?v_cur_data;
          end;
          posted on 2007-01-18 16:27 滌生 閱讀(8461) 評論(6)  編輯  收藏


          FeedBack:
          # re: IBatis的分頁研究
          2007-01-18 17:29 | BeanSoft
          是呀, 學習 ORM 工具的時候, 還是得熟悉 JDBC 和 SQL 的, 要不然系統瓶頸了就沒招了.  回復  更多評論
            
          # re: IBatis的分頁研究
          2007-01-18 18:31 | 滌生
          @BeanSoft
          說的甚是,尤其是遇到一些典型的會出現性能問題的地方,一定要研究一下所使用ORM工具的實現方法。既要知其然,又要知其所以然
            回復  更多評論
            
          # re: IBatis的分頁研究
          2007-01-18 18:33 | 布衣郎
          不錯,支持一下,使用數據庫本身的分頁方法,對效率有所幫助,如果數據量不大,可以采用ibatis默認的方法。  回復  更多評論
            
          # re: IBatis的分頁研究
          2007-01-18 20:36 | 劍事
          用了快一年了
          也算選對了  回復  更多評論
            
          # re: IBatis的分頁研究
          2007-02-11 11:19 | str
          很多的ORM框架實際都是用數據庫自己帶的分頁方式。。  回復  更多評論
            
          # re: IBatis的分頁研究
          2008-07-08 16:56 | 汽車
          性能是個大問題  回復  更多評論
            

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


          網站導航:
           
          <2007年1月>
          31123456
          78910111213
          14151617181920
          21222324252627
          28293031123
          45678910

          常用鏈接

          留言簿(5)

          隨筆檔案

          UML

          搜索

          •  

          最新評論

          閱讀排行榜

          評論排行榜

          主站蜘蛛池模板: 安泽县| 德昌县| 翼城县| 永州市| 微博| 民勤县| 古交市| 大洼县| 冀州市| 板桥市| 班戈县| 自治县| 福建省| 隆昌县| 隆化县| 磐石市| 新丰县| 阜阳市| 大竹县| 漾濞| 威海市| 永靖县| 阿荣旗| 上犹县| 廉江市| 华阴市| 宜兰县| 孟村| 鄯善县| 方正县| 普陀区| 都昌县| 绍兴市| 永修县| 白城市| 荃湾区| 时尚| 中方县| 上饶市| 本溪| 云安县|