好學(xué)驛站

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

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

          Hibernate 可以實(shí)現(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底層如何實(shí)現(xiàn)分頁的呢?實(shí)際上Hibernate的查詢定義在net.sf.hibernate.loader.Loader這個(gè)類里面,仔細(xì)閱讀該類代碼,就可以把問題徹底搞清楚。

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

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

          如果相應(yīng)的數(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層的查詢語句結(jié)合rownum來實(shí)現(xiàn)分頁,這在Oracle上是最快的方式,如果只是一層或者兩層的查詢語句的rownum不能支持order by。

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

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

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

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


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

          主站蜘蛛池模板: 驻马店市| 元江| 广灵县| 固镇县| 定兴县| 确山县| 湄潭县| 石狮市| 寻乌县| 平泉县| 博客| 红安县| 郓城县| 宜都市| 岳阳市| 兴城市| 仁怀市| 栾川县| 宜黄县| 门头沟区| 灵台县| 泌阳县| 类乌齐县| 武城县| 香河县| 丰顺县| 临汾市| 娄底市| 库尔勒市| 萝北县| 察隅县| 安平县| 章丘市| 荔浦县| 巴中市| 会东县| 北碚区| 遂溪县| 当阳市| 江山市| 灵寿县|