Hibernate 可以实现分页查询 如下
Query q = session.createQuery("from Cat as c");
q.setFirstResult(10000);
q.setMaxResults(20);
List l = q.list();
生成的sql 语句为
select top 10000 .... from Cat as c
分析:Hibernate 获取到 10000条记录过后再筛选出符合条件的20条记录。

再来看看Hibernate 的 dialect 对 sql server 怎样分页的
public String getLimitString(String querySelect, int offset, int limit) {
      if ( offset > 0 ) {
           throw new UnsupportedOperationException( "sql server has no offset" );
        }
       return new StringBuffer( querySelect.length() + 8 )
                .append( querySelect )
                .insert( getAfterSelectInsertPoint( querySelect ), " top " + limit )
                .toString();
  }
由此可以看出Hibernate对 sql server 分页全是采取 top 方式来处理。如记录有10W条以上的话到后面几页效率会非常低。从getLimitString(String querySelect, int offset, int limit)方法可以看出 sql server 不支持 offset 参数(均为0)!!

然而在sql server2005过后支持ROW_NUMBER() 函数,可用该函数大大提高分页效率。但现有的Hibernate api不支持该函数。我们可以重写public String getLimitString(String querySelect, int offset, int limit)方法来实现 ROW_NUMBER 分页,重写的方法如下:
    public String getLimitString(String querySelect, int offset, int limit ){
        int lastIndexOfOrderBy = getLastIndexOfOrderBy(querySelect);
        // 没有 order by 或第一页的情况下
        if(lastIndexOfOrderBy<0 || querySelect.endsWith(")") || offset==0)
            return super.getLimitString(querySelect, 0, limit);
        else {
            //取出 order by 语句
            String orderby = querySelect.substring(lastIndexOfOrderBy, querySelect.length());
            //取出 from 前的内容
            int indexOfFrom = querySelect.toLowerCase().indexOf("from");
            String selectFld = querySelect.substring(0,indexOfFrom);
            //取出 from 语句后的内容
            String selectFromTableAndWhere = querySelect.substring(indexOfFrom, lastIndexOfOrderBy);
            StringBuffer sql = new StringBuffer(querySelect.length()+100);
            sql.append("select * from (")
                .append(selectFld)
                .append(",ROW_NUMBER() OVER(").append(orderby).append(") as _page_row_num_hb ")
                .append(selectFromTableAndWhere).append(" ) temp ")
                .append(" where  _page_row_num_hb BETWEEN  ")
                .append(offset+1).append(" and ").append(limit);
            return sql.toString();
        }
    }
让offset参数有效还应重写 public boolean supportsLimitOffset() 方法
    public boolean supportsLimitOffset(){
        return true;
    }

完整的代码如下:
package org.jac.common;
import org.hibernate.dialect.SQLServerDialect;
public class JacSQLServerDialect extends SQLServerDialect {
    static int getLastIndexOfOrderBy(String sql){
        return sql.toLowerCase().lastIndexOf("order by ");
    }
   
    public String getLimitString(String querySelect, int offset, int limit ){
        int lastIndexOfOrderBy = getLastIndexOfOrderBy(querySelect);
        // 没有 order by 或第一页的情况下
        if(lastIndexOfOrderBy<0 || querySelect.endsWith(")") || offset==0)
            return super.getLimitString(querySelect, 0, limit);
        else {
            //取出 order by 语句
            String orderby = querySelect.substring(lastIndexOfOrderBy, querySelect.length());
            //取出 from 前的内容
            int indexOfFrom = querySelect.toLowerCase().indexOf("from");
            String selectFld = querySelect.substring(0,indexOfFrom);
            //取出 from 语句后的内容
            String selectFromTableAndWhere = querySelect.substring(indexOfFrom, lastIndexOfOrderBy);
            StringBuffer sql = new StringBuffer(querySelect.length()+100);
            sql.append("select * from (")
                .append(selectFld)
                .append(",ROW_NUMBER() OVER(").append(orderby).append(") as _page_row_num_hb ")
                .append(selectFromTableAndWhere).append(" ) temp ")
                .append(" where  _page_row_num_hb BETWEEN  ")
                .append(offset+1).append(" and ").append(limit);
            return sql.toString();
        }
    }
    //使offset 参数生效
    public boolean supportsLimitOffset(){
        return true;
    }
最后再 hibernate.cfg.xml 配置 dialect
<property name="dialect">
      org.jac.common.JacSQLServerDialect
</property>

测试结果如下:
Query q = session.createQuery("from Cat as c order by c.id asc"); //注意要加 order by 才能用到 ROW_NUMBER分页
q.setFirstResult(10000);
q.setMaxResults(20);
List l = q.list();
生成的sql 语句为
select * from (select   ....,ROW_NUMBER() OVER(order by cat0_.id asc) as _page_row_num_hb from
cat as cat0_) temp where _page_row_num_hb BETWEEN  10001 and 10020

hibernate 对 sql server 2005 分页改进的更多相关文章

  1. 解决hibernate对Sql Server分页慢的问题

    一.hibernate分页 hibernate对MsSql的伪分页 分页是web项目中比不可少的一个功能,数据量大的时候不能全部展示必然要用到分页技术.相信大家对hibernate中的分页都不陌生: ...

  2. 使用SQL Server 2005 新的语法ROW_NUMBER()进行分页的两种不同方式的性能比较

    相比在SQL Server 2000 中使用的分页方式,在SQL Server 2005中使用新的语法ROW_NUMBER()来分页效率要高出很多,但是很多人在使用ROW_NUMBER()这种分页方式 ...

  3. SQL Server 2005的几个新功能

    SQL Server 2005相对于SQL Server 2000改进很大,有些还是非常实用的. 举几个例子来简单说明 这些例子我引用了Northwind库. 1. TOP 表达式  SQL Serv ...

  4. 回首经典的SQL Server 2005

    原创文章转载请注明出处:@协思, http://zeeman.cnblogs.com SQL Server是我使用时间最长的数据库,算起来已经有10年了.上世纪90年代,微软在软件开发的所有领域高歌猛 ...

  5. 转载--SQL Server 2005的XQuery介绍

    原文地址: http://bbs.51cto.com/thread-458009-1-1.html   引用: 摘要 本文介绍了SQL Server 2005能够支持的XQuery的各方面特性如FLW ...

  6. 配置MyEclipse+Hibernate连接Sql Server 2008出错

    下文主要是讲述最近配置MyEclipse连接Sql Server 2008时遇到的一个问题,而不关注如何配置Sql Server 2008支持TCP/IP连接.Hibernate如何操作Sql Ser ...

  7. SQL Server 存储过程分页

    每每面试,总会有公司问到分页.在下不才,在这里写几种分页,望路过的各位大神尽情拍砖. 先从创建数据库说起.源码如下 一.创建数据库 /********************************* ...

  8. Sql Server 2005的1433端口打开和进行远程连接

    参考地址:http://topic.csdn.net/u/20090828/16/e693935a-99b7-4090-a6bc-0123c91183eb.html 1.如何打开sql server  ...

  9. 使用XML向SQL Server 2005批量写入数据——一次有关XML时间格式的折腾经历

    原文:使用XML向SQL Server 2005批量写入数据——一次有关XML时间格式的折腾经历 常常遇到需要向SQL Server插入批量数据,然后在存储过程中对这些数据进行进一步处理的情况.存储过 ...

随机推荐

  1. 世界最大射电望远镜(Arecibo)用于探測地外文明

    请看下图: 这是眼下世界最大口径(305米)射电望远镜的外观图,位于美国中西部的PuertoRico州,建成于1963年,工作波段在3厘米至1米波段范围内,正好适合用于探測地外文明(SETI)的科学研 ...

  2. 动态从数据库读取菜单(ASP.NET版)

    这几天一直打算做个从数据读取导航菜单的效果,以前做的时候都是写死的(太死了),好了话不多说,先看效果! 我是个小菜,高手请不要喷!我在网上查了好久,说用menu控件,但是我用了不太好!最后我决定用re ...

  3. Sass函数--字符串函数

    Sass的函数简介在 Sass 中除了可以定义变量,具有 @extend.%placeholder 和 mixins 等特性之外,还自备了一系列的函数功能.其主要包括: ● 字符串函数 ● 数字函数 ...

  4. html 使用表单标签,与用户交互

    使用表单标签,与用户交互 网站怎样与用户进行交互?答案是使用HTML表单(form).表单是可以把浏览者输入的数据传送到服务器端,这样服务器端程序就可以处理表单传过来的数据. 语法: <form ...

  5. (转)在Repeater中嵌套使用Repeater

    在一般的网站中浏览类别的用户控件通常都位于大多数 ASP.NET 页的左边,它使用户能够按类别快速的查找产品.最近遇到一个客户,因为在他网站上展示的产品并不多,所以要求在原有类别浏览的基础上将产品也加 ...

  6. AngularJs练习Demo13Provider_factory

    @{ Layout = null; } <!DOCTYPE html> <html> <head> <meta name="viewport&quo ...

  7. taglib的使用

    使用自定义的taglib可以是我们对页面数据的处理放在后台,不仅使用方便,而且影藏了处理逻辑,也更加的安全. 需要使用到servlet.jar 1.在web-inf下建立taglib.tld文件 &l ...

  8. linux目录权限小记

    r : 拥有读取目录结构列表的权限 x:拥有进入此目录的权限 w: 1: 建立新的档案和目彔: 2删除已经存在的档案和目录(无论该档案的权限为何!) 3能够重命名档案和目录: 4 能够移动目录里面的 ...

  9. oracle数据库实验讲义-读书笔记(一)

    1.激活锁定的用户alter user scott account unlock identified by tiger;2.使用内含脚本建立scott用户@%oracle_home%\rdbms\a ...

  10. PYTHON-进阶-ITERTOOLS模块

    PYTHON-进阶-ITERTOOLS模块小结 这货很强大, 必须掌握 文档 链接 pymotw 链接 基本是基于文档的翻译和补充,相当于翻译了 itertools用于高效循环的迭代函数集合 组成 总 ...