好學驛站

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

          Hibernate實現(xiàn)分頁查詢的原理分析

          Hibernate 可以實現(xiàn)分頁查詢,例如:
          從第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底層如何實現(xiàn)分頁的呢?實際上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);??

          如果相應的數(shù)據(jù)庫定義了限定查詢記錄的sql語句,那么直接使用特定數(shù)據(jù)庫的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來實現(xiàn)分頁,這在Oracle上是最快的方式,如果只是一層或者兩層的查詢語句的rownum不能支持order by。

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

          如果數(shù)據(jù)庫不支持分頁的SQL語句,那么根據(jù)在配置文件里面
          #hibernate.jdbc.use_scrollable_resultset true
          默認是true,如果你不指定為false,那么Hibernate會使用JDBC2.0的scrollable result來實現(xiàn)分頁,看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方法直接移到查詢起點,如果不支持的話,使用循環(huán)語句,rs.next一點點的移過去。

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

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


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

          主站蜘蛛池模板: 来安县| 万载县| 永安市| 策勒县| 拜泉县| 金乡县| 霍林郭勒市| 普格县| 长岭县| 河津市| 公安县| 弥渡县| 柳河县| 玉溪市| 仲巴县| 双城市| 忻城县| 西安市| 汉中市| 克东县| 郓城县| 大姚县| 宣汉县| 合川市| 哈巴河县| 丰宁| 霍州市| 佛坪县| 乌鲁木齐县| 定日县| 全南县| 崇义县| 卢龙县| 县级市| 巴林左旗| 江川县| 苏尼特右旗| 哈密市| 枣庄市| 尼玛县| 大名县|