转自:http://blog.csdn.net/huqiub/article/details/4329541

分页在任何系统中都是非常头疼的事情,有的数据库在语法上支持分页,而有的数据库则需要使用可滚动游标来实现,并且在不支持可滚动游标的系统上只能使用单向游标逐步接近要取得的数据。
     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()移动的办法。这样既兼顾了查询分页的性能,同时又保证了代码在不同的数据库之间的可移植性。

Hibernate实现分页的更多相关文章

  1. Hibernate中分页

    query.setFirstResult(4);query.setMaxResults(5);       这两个方法就是hibernate的分页

  2. hibernate 的分页查询

    hibernate的分页查询有个好处,就是不用管数据库方言.比如db2的分页查询很麻烦,但是用hibernate的方式,就完全不用管这些了 /* 使用HQL分页查询Customer信息 */ publ ...

  3. struts2+spring+hibernate 实现分页

    在这里要感谢下这位博友发表的博文 http://www.blogjava.net/rongxh7/archive/2008/11/29/243456.html 通过对他代码的阅读,从而自己实现了网页分 ...

  4. hibernate 实现分页查询语句、单条查询语句、多条查询语句、修改、删除语句

    package com.hanqi.test; import java.util.Date; import java.util.List; import org.hibernate.Query; im ...

  5. Hibernate简单分页

    5.1 准备工作 建立项目,加入jar 建立hibernate.cfg.xml 建立pojo类和对应的映射文件 5.2 建立vo类PageEntity package org.guangsoft.vo ...

  6. Hibernate 条件-分页查询

    这里我们继续跟着上一次的节奏继续学习Hibernate的查询. 1.条件查询一(占位符) 按照占位符的方式进行条件查询,这里query有一个setInteger(arg1, arg2)方法,其中第一个 ...

  7. hibernate mysql 分页时报错 显示的代码和sql server 类似 select top 1……

    [ERROR][com.alibaba.druid.filter.stat.StatFilter]merge sql error, dbType mysql, sql : select top 1 d ...

  8. 用Hibernate实现分页查询

    分页查询就是把数据库中某张表的记录数进行分页查询,在做分页查询时会有一个Page类,下面是一个Page类,我对其做了详细的注解: package com.entity; /** * @author:秦 ...

  9. Hibernate实现分页查询

    分页查询就是把数据库中某张表的记录数进行分页查询,在做分页查询时会有一个Page类,下面是一个Page类,我对其做了详细的注解: 1 package com.entity; 2 /** 3 * @au ...

随机推荐

  1. 使用SQLiteHelper创建数据库并插入数据

    参考<疯狂android讲义>8.4节P424 1.获取SQLiteDatabase实例有2种方法,一是直接new SQLiteDatabase(),另一种使用SQLiteHelper.一 ...

  2. Android 从AndroidManifest获取meta-data

    语法如下: <meta-data android:name="string" android:resource="resource specification&qu ...

  3. Python之路第十天,高级(2)-多线程,多进程,协程

    线程 threading threading模块对象 描述 Thread 表示一个线程的执行对象 Lock 锁原语对象 RLock 可重入锁对象,使单线程可再次获得已经获得了的锁(递归锁定) Cond ...

  4. 注册表添加python

    win(python2.7)下: 执行此文件 #!/usr/bin/env python # encoding:utf-8 # # script to register Python 2.0 or l ...

  5. 看懂这个sql 你的sql语句就掌握了

    某财务报表 USE [PB_AHTC]GO/****** Object: StoredProcedure [dbo].[JSPRO] Script Date: 12/10/2013 11:54:52 ...

  6. Git学习04 --分支管理

    每次commit,Git都把它们串成一条时间线,这条时间线就是一个分支.截止到目前,只有一条时间线,在Git里,这个分支叫主分支,即master分支.HEAD严格来说不是指向提交,而是指向master ...

  7. C 语言的可变参数表函数的设计

    在c语言中使用变长参数最常见的就是下面两个函数了: int printf(const char *format, ...); int scanf(const char *format, ...); 那 ...

  8. CSS 注意事项

    使用css缩写   使用缩写可以帮助减少你CSS文件的大小,更加容易阅读. 明确定义单位,除非值为0 忘记定义尺寸的单位是CSS新手普遍的错误.在HTML中你可以只写width="100&q ...

  9. Stackoverflow上人气最旺的10个Java问题(转ImportNew)

    本文转自:http://www.importnew.com/16841.html 写的确实太好了 1.为什么两个(1927年)时间相减得到一个奇怪的结果? 如果执行下面的程序,程序解析两个间隔1秒的日 ...

  10. linux动态库加载的秘密

    摘自http://gotowqj.iteye.com/blog/1926734 摘自http://www.360doc.com/content/14/0313/13/12747488_36024641 ...