好學驛站

          JSP、JAVA、struts、hibernate、spring、eclipse、工作流、電子政務、協同辦公、J2ME

          Hibernate實現分頁查詢的原理分析

          Hibernate 可以實現分頁查詢,例如:
          從第2萬條開始取出100條記錄

          代碼
          1. Query?q?=?session.createQuery( "from?Cat?as?c" ); ??
          2. q.setFirstResult( 20000 ); ??
          3. q.setMaxResults( 100 ); ??
          4. List?l?=?q.list();??

          那么Hibernate底層如何實現分頁的呢?實際上Hibernate的查詢定義在net.sf.hibernate.loader.Loader這個類里面,仔細閱讀該類代碼,就可以把問題徹底搞清楚。

          Hibernate2.0.3的Loader源代碼第480行以下:

          代碼
          1. if ?(useLimit)?sql?=?dialect.getLimitString(sql);???????? ??
          2. PreparedStatement?st?=?session.getBatcher().prepareQueryStatement(sql,?scrollable);??

          如果相應的數據庫定義了限定查詢記錄的sql語句,那么直接使用特定數據庫的sql語句。

          然后來看net.sf.hibernate.dialect.MySQLDialect:

          代碼
          1. public ? boolean ?supportsLimit()?{ ??
          2. ?? return ? true ; ??
          3. } ??
          4. public ?String?getLimitString(String?sql)?{ ??
          5. ??StringBuffer?pagingSelect?=? new ?StringBuffer( 100 ); ??
          6. ??pagingSelect.append(sql); ??
          7. ??pagingSelect.append( "?limit??,??" ); ??
          8. ?? return ?pagingSelect.toString(); ??
          9. }??

          這是MySQL的專用分頁語句,再來看net.sf.hibernate.dialect.Oracle9Dialect:

          代碼
          1. public ? boolean ?supportsLimit()?{ ??
          2. ?? return ? true ; ??
          3. } ??
          4. ??
          5. public ?String?getLimitString(String?sql)?{ ??
          6. ??StringBuffer?pagingSelect?=? new ?StringBuffer( 100 ); ??
          7. ??pagingSelect.append( "select?*?from?(?select?row_.*,?rownum?rownum_?from?(?" ); ??
          8. ??pagingSelect.append(sql); ??
          9. ??pagingSelect.append( "?)?row_?where?rownum?<=??)?where?rownum_?>??" ); ??
          10. ?? return ?pagingSelect.toString(); ??
          11. }??

          Oracle采用嵌套3層的查詢語句結合rownum來實現分頁,這在Oracle上是最快的方式,如果只是一層或者兩層的查詢語句的rownum不能支持order by。

          除此之外,Interbase,PostgreSQL,HSQL也支持分頁的sql語句,在相應的Dialect里面,大家自行參考。

          如果數據庫不支持分頁的SQL語句,那么根據在配置文件里面
          #hibernate.jdbc.use_scrollable_resultset true
          默認是true,如果你不指定為false,那么Hibernate會使用JDBC2.0的scrollable result來實現分頁,看Loader第430行以下:

          代碼
          1. if ?(?session.getFactory().useScrollableResultSets()?)?{ ??
          2. ?? //?we?can?go?straight?to?the?first?required?row ??
          3. ??rs.absolute(firstRow); ??
          4. } ??
          5. else ?{ ??
          6. ?? //?we?need?to?step?through?the?rows?one?row?at?a?time?(slow) ??
          7. ?? for ?(? int ?m= 0 ;?m<firstRow;?m++?)?rs.next(); ??
          8. }??

          如果支持scrollable result,使用ResultSet的absolute方法直接移到查詢起點,如果不支持的話,使用循環語句,rs.next一點點的移過去。

          可見使用Hibernate,在進行查詢分頁的操作上,是具有非常大的靈活性,Hibernate會首先嘗試用特定數據庫的分頁sql,如果沒用,再嘗試Scrollable,如果不行,最后采用rset.next()移動的辦法。

          在查詢分頁代碼中使用Hibernate的一大好處是,既兼顧了查詢分頁的性能,同時又保證了代碼在不同的數據庫之間的可移植性。


          posted on 2007-06-13 11:10 好學蜘蛛 閱讀(241) 評論(0)  編輯  收藏 所屬分類: JAVA 、hibernate

          主站蜘蛛池模板: 忻城县| 阿合奇县| 杨浦区| 乌兰县| 神农架林区| 宁远县| 周口市| 华容县| 平塘县| 甘洛县| 红桥区| 平泉县| 栾城县| 萨迦县| 班戈县| 孝昌县| 汝南县| 安徽省| 吐鲁番市| 米泉市| 中山市| 阿巴嘎旗| 延长县| 上虞市| 弥渡县| 沙坪坝区| 颍上县| 土默特左旗| 改则县| 宜章县| 平利县| 萝北县| 新乡市| 四川省| 岳普湖县| 定州市| 梨树县| 明光市| 洪湖市| 东阿县| 铅山县|