JR 精品文章 - hibernate分页
AD: jr (at) javaresearch.org


首页 | 动态 | 文章 | FAQ  | 新闻 | 下载 | 代码 | 工作 | 调查 | 术语 | 站点 | 图书 | 论坛 | 帮助 | 全部  

TOP | 交流 | 软件 | 专栏 | 开源 | 译/著 | 源码 | API  | 推荐 | FTP  | 积分 | 统计 | 搜索 | Blog | 我们  
首页 » 研究文集 » 开发框架 搜索标题相关文章 搜索标题相关文章    评论此文章 发表评论     开始监控此文章 开始监控   加入收藏夹  加入收藏夹
hibernate分页
cownew 整理   更新:2007-03-07 09:29:04  版本: 1.0   

分页在任何系统中都是非常头疼的事情,有的数据库在语法上支持分页,而有的数据库则需要使用可滚动游标来实现,并且在不支持可滚动游标的系统上只能使用单向游标逐步接近要取得的数据。
 Hibernate提供了一个支持跨系统的分页机制,这样无论底层是什么样的数据库都能用统一的接口进行分页操作。比如下面的代码就是从第500条开始取出100条记录: 
Query q = session.createQuery("from FooBar as f"); 
q.setFirstResult(500); 
q.setMaxResults(100); 
List l = q.list(); 
那么Hibernate底层如何实现分页的呢?Hibernate根据Query拼装SQL语句的地方是在org.hibernate.loader.Loader类的prepareQueryStatement方法中,对分页支持的代码在这一段中可以发现:
if (useLimit) 
{
sql = dialect.getLimitString( 
     sql.trim(), //use of trim() here is ugly?
     useOffset ? getFirstRow(selection) : 0, 
     getMaxOrLimit(selection, dialect) 
    );
 }
 此处调用Dialect的getLimitString方法来得到不同平台的分页语句。
在MySQLDialect中是如下实现getLimitString方法的:
public String getLimitString(String sql, boolean hasOffset) 
{
return new StringBuffer( sql.length()+20 )
.append(sql)
.append( hasOffset ? " limit ?, ?" : " limit ?")
.toString();
}
 这是MySQL的专用分页语句,再来看Oracle9Dialect:
 public String getLimitString(String sql, boolean hasOffset) {
  
  sql = sql.trim();
  boolean isForUpdate = false;
  if ( sql.toLowerCase().endsWith(" for update") ) {
   sql = sql.substring( 0, sql.length()-11 );
   isForUpdate = true;
  }
  
  StringBuffer pagingSelect = new StringBuffer( sql.length()+100 );
  if (hasOffset) {
   pagingSelect.append("select * from ( select row_.*, rownum rownum_ from ( ");
  }
  else {
   pagingSelect.append("select * from ( ");
  }
  pagingSelect.append(sql);
  if (hasOffset) {
   pagingSelect.append(" ) row_ where rownum <= ?) where rownum_ > ?");
  }
  else {
   pagingSelect.append(" ) where rownum <= ?");
  }

  if ( isForUpdate ) {
   pagingSelect.append( " for update" );
  }
  
  return pagingSelect.toString();
 } 
Oracle采用嵌套3层的查询语句结合rownum来实现分页,这在Oracle上是最好的方式,因为如果只是一层或者两层的查询语句的rownum不能支持order by。
此外Interbase,PostgreSQL,HSQL等也在语法级别上支持分页,具体实现可以查看相应的Dialect实现。如果数据库不支持分页的SQL语句,那么如果数据库支持可滚动游标,那么Hibernate就会采使用ResultSet的absolute方法直接移到查询起点;否则使用循环语句,通过rs.next一步步移动到要查询的数据处: 
final int firstRow = getFirstRow( selection );
if ( firstRow != 0 ) 
{
if ( getFactory().getSettings().isScrollableResultSetsEnabled() ) 
{
// we can go straight to the first required row
rs.absolute( firstRow );
}
else 
{
// we need to step through the rows one row at a time (slow)
for ( int m = 0; m < firstRow; m++ ) rs.next();
}
}

可见使用Hibernate,在进行查询分页的操作上,是具有非常大的灵活性,Hibernate会首先尝试用特定数据库的分页sql,如果没用,再尝试Scrollable,如果不支持Scrollable再采用rset.next()移动的办法。这样既兼顾了查询分页的性能,同时又保证了代码在不同的数据库之间的可移植性。 




版权声明  
本篇文章对您是否有帮助?  投票:         投票结果:     13       1
作者其它文章: 作者全部文章
评论人:hoton 发表时间: Thu Mar 08 12:13:15 CST 2007
太好了....
评论人:lwb996140066666666 发表时间: Tue Apr 10 18:22:59 CST 2007
[java]
评论人:singsongzw 发表时间: Thu May 03 18:18:12 CST 2007
我顶一下
评论人:yanglenovo 发表时间: Tue Aug 21 03:23:38 CST 2007
好啊[:)]

这个文章共有 4 条评论
主题: 正则表达式快速入门 上一篇文章
返回文章列表 返回〔开发框架〕
下一篇文章 主题: eclipse调试原理解惑!


文字广告链接
        自主、快速定制基于JAVA的B/S业务系统          重量级企业在线自定义WEB报表平台
        Excel制表、零代码发布、打印、图表结合——快逸报表,免费、稳定、功能强大的java工具
        技术圈: 关于Java、dotNet、PHP、Ruby、奇客、Web2.0等更多资讯博客精选文章

关于 JR  |  版权声明  |  联系我们 

©2002-2006 JR 版权所有 沪ICP备05019622号