论坛首页 入门技术论坛

Hibernate如何实现分页的?

浏览 2417 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2009-12-17  

 

解决项目中一问题时, 由于涉及到Hibernate的分页功能, 于是打草兔子地研究了下Hibernate分页功能的实现。

 

我们先来看用Hibernate来实现分页的代码片段:

       Criteria c = session.createCriteria(Area.class);

      

       c.setFirstResult(10);

       c.setMaxResults(20);

      

       List list = c.list();

 

上面c.list()执行后,就看到了满足条件的十条记录,即第1120这十条。

 

那么在Hibernate内部这是怎么实现的呢?

 

截下了Hibernate生成的sql(如何截,请见另一篇博文:Hibernate初始化时如何生成SQL语句?),它是这样的:

    select a.* from

 

(

  select row_.*, rownum rownum_ from

  ( select this_.id as id0_0_, this_.ALIAS_ID as ALIAS2_0_0_, this_.COMM as COMM0_0_, this_.CREATE_TIME as CREATE4_0_0_, this_.NAME as NAME0_0_ from AREA this_ ) row_

  where rownum <= 20

)  a

 

where a.rownum_ > 10

    注:为了下文说明方便,上面sql是我又加了些东东,如a和参数(1020)。

那么这个sql是怎么生成的呢?

Debug过程中,经历了超人般的跨越后,最终在org.hibernate.dialect.Oracle9Dialect中的getLimitString方法中,看到了整个sql的组装过程。

 

 

源码就不粘在这了, 看它的原理,发现它巧妙地利用了Oracle数据中的伪列rownum  

 

这里的sql有两个临时表 row_ a

l  第一个表row_里包含了满足条件的所有结果, 可能是1000条。

l  第二个表a,这里利用Oracle的伪列rownum 取前20条, 并把这个伪列rownum(临时值)作为表a的一个真正存在的列保存下来, 这样就能光明正大地用a.rownum_ > 10过滤条件了。

 

 

至此,解释并记录完毕, 收队!

 

   发表时间:2009-12-17  
SELECT xx.* FROM
(
SELECT t.*,row_number() over(ORDER BY id ) AS num
FROM tableName t
)xx

WHERE num BETWEEN 5 AND 15;

据说效率更高些。

http://www.java2s.com/Code/Oracle/Analytical-Functions/ROWNUMBERreturnanumberwitheachrowinagroupstartingat1.htm
0 请登录后投票
   发表时间:2010-08-22  
rmn190 写道
SELECT xx.* FROM
(
SELECT t.*,row_number() over(ORDER BY id ) AS num
FROM tableName t
)xx

WHERE num BETWEEN 5 AND 15;

据说效率更高些。

http://www.java2s.com/Code/Oracle/Analytical-Functions/ROWNUMBERreturnanumberwitheachrowinagroupstartingat1.htm


这样在order by时,有问题,参见:http://www.blogjava.net/joessy/articles/1398.html
0 请登录后投票
   发表时间:2010-08-22  
好久没接触过Oracle里这个特性了,关于rownum的确切含义也忘完了,于是google一番后,找到下面这个简明的解释,

来源:http://bytes.com/topic/oracle/answers/739592-working-rownum-oracle中的第4楼。

解释:

rownum is assigned to rows AS THEY SATISFY the predicate.
the logic would be:
   rownum = 1
   for x in ( select * from A )
   loop
       if ( x satisifies the predicate ) 
       then
             OUTPUT the row
             rownum = rownum + 1
       end if;
   end loop;



in the case of where rownum = 1, the first row passes the test, is output and rownum goes
to 2. No other row ever satisfies the predicate and rownum stays at 2 for the rest of
the query.

in the case of where rownum = 2, the first row is rownum 1, it fails. The next row is
ALSO rownum = 1 and likewise fails. And so on. There can be NO row 2 if there is not a
row 1.

THE ROWNUM -- is incremented only AFTER the row is output
0 请登录后投票
论坛首页 入门技术版

跳转论坛:
Global site tag (gtag.js) - Google Analytics