`
xiongzhenhui
  • 浏览: 209763 次
  • 性别: Icon_minigender_1
  • 来自: 厦门
社区版块
存档分类
最新评论

扩展hibernate的方言。使hibernate支持row_number

阅读更多

hibernate对于sqlserver2005真分页

Hibernate分页的“真”与“假”,取决于所指定的方言(Dialect)。分析了一下Hibernate中相关的源代码,目前的结论是:OracleDialect、Oracle9Dialect、MySQLDialect、MySQL5Dialect是真分页,SQLServerDialect是假分页。
Hibernate 可以实现分页查询 如下
1 Query q = session.createQuery("from Cat as c");
2 q.setFirstResult(10000);
3 q.setMaxResults(20);
4 List l = q.list();
生成的sql 语句为
select top 10000 .... from Cat as c
分析:Hibernate 获取到 10000条记录过后再筛选出符合条件的20条记录。

再来看看Hibernate 的 dialect 对 sql server 怎样分页的
1 public String getLimitString(String querySelect, int offset, int limit) {
2       if ( offset > 0 ) {
3            throw new UnsupportedOperationException( "sql server has no offset" );
4         }
5        return new StringBuffer( querySelect.length() + 8 )
6                 .append( querySelect )
7                 .insert( getAfterSelectInsertPoint( querySelect ), " top " + limit )
8                 .toString();
9   }

由此可以看出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 分页,重写的方法如下:
01 public String getLimitString(String querySelect, int offset, int limit ){
02     int lastIndexOfOrderBy = getLastIndexOfOrderBy(querySelect);
03     // 没有 order by 或第一页的情况下
04     if(lastIndexOfOrderBy<0 || querySelect.endsWith(")") || offset==0)
05         return super.getLimitString(querySelect, 0, limit);
06     else {
07         //取出 order by 语句
08         String orderby = querySelect.substring(lastIndexOfOrderBy, querySelect.length());
09         //取出 from 前的内容
10         int indexOfFrom = querySelect.toLowerCase().indexOf("from");
11         String selectFld = querySelect.substring(0,indexOfFrom);
12         //取出 from 语句后的内容
13         String selectFromTableAndWhere = querySelect.substring(indexOfFrom, lastIndexOfOrderBy);
14         StringBuffer sql = new StringBuffer(querySelect.length()+100);
15         sql.append("select * from (")
16             .append(selectFld)
17             .append(",ROW_NUMBER() OVER(").append(orderby).append(") as _page_row_num_hb ")
18             .append(selectFromTableAndWhere).append(" ) temp ")
19             .append(" where  _page_row_num_hb BETWEEN  ")
20             .append(offset+1).append(" and ").append(limit);
21         return sql.toString();
22     }
23 }

让offset参数有效还应重写 public boolean supportsLimitOffset() 方法
    public boolean supportsLimitOffset(){
        return true;
    }

完整的代码如下:
01 package com.java1995.dialect;
02 import org.hibernate.dialect.SQLServerDialect;
03 public class Java1995SQLServerDialect extends SQLServerDialect {
04     static int getLastIndexOfOrderBy(String sql){
05         return sql.toLowerCase().lastIndexOf("order by ");
06     }
07      
08     public String getLimitString(String querySelect, int offset, int limit ){
09         int lastIndexOfOrderBy = getLastIndexOfOrderBy(querySelect);
10         // 没有 order by 或第一页的情况下
11         if(lastIndexOfOrderBy<0 || querySelect.endsWith(")") || offset==0)
12             return super.getLimitString(querySelect, 0, limit);
13         else {
14             //取出 order by 语句
15             String orderby = querySelect.substring(lastIndexOfOrderBy, querySelect.length());
16             //取出 from 前的内容
17             int indexOfFrom = querySelect.toLowerCase().indexOf("from");
18             String selectFld = querySelect.substring(0,indexOfFrom);
19             //取出 from 语句后的内容
20             String selectFromTableAndWhere = querySelect.substring(indexOfFrom, lastIndexOfOrderBy);
21             StringBuffer sql = new StringBuffer(querySelect.length()+100);
22             sql.append("select * from (")
23                 .append(selectFld)
24                 .append(",ROW_NUMBER() OVER(").append(orderby).append(") as _page_row_num_hb ")
25                 .append(selectFromTableAndWhere).append(" ) temp ")
26                 .append(" where  _page_row_num_hb BETWEEN  ")
27                 .append(offset+1).append(" and ").append(limit);
28             return sql.toString();
29         }
30     }
31     //使offset 参数生效
32     public boolean supportsLimitOffset(){
33         return true;
34     }

最后再 hibernate.cfg.xml 配置 dialect
<property name="dialect">
      com.java1995.dialect.Java1995SQLServerDialect
</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 方言 2.0 至 4.0

    5. **新功能支持**:随着Hibernate的进化,新版本的方言也会引入对如批处理操作、存储过程调用等新功能的支持,使开发者能更好地利用达梦数据库的高级特性。 6. **错误修复**:每个版本迭代通常会包含对已知问题的...

    hibernate-cglib-repack-2.1_3.jar

    总的来说,"hibernate-cglib-repack-2.1_3.jar"是Hibernate框架中不可或缺的一部分,它通过CGLIB库实现了对Java类的动态代理,提供了诸如懒加载、拦截器等高级功能,极大地增强了ORM的灵活性和可扩展性。在实际开发...

    达梦Hibernate方言2.0至4.0

    这里我们关注的是“达梦Hibernate方言2.0至4.0”,这是一个专为达梦数据库系统(DM)设计的Hibernate方言支持,涵盖了Hibernate框架的多个版本。Hibernate是一个流行的Java对象关系映射(ORM)框架,它允许开发人员...

    达梦数据库hibernate方言包

    达梦数据库各版本的hibernate方言包,包含版本 DmDialect-for-hibernate2.0、DmDialect-for-hibernate2.1、DmDialect-for-hibernate3.0、DmDialect-for-hibernate3.1、DmDialect-for-hibernate3.6、DmDialect-for-...

    GBase_Hibernate3.2.3_GA-Dialect_8.3.81.51_build50.1.jar

    南大通用GBase数据库GBase_Hibernate3.2.3_GA-Dialect_8.3.81.51_build50.1.jar

    Hibernate_3.2.0_Reference_zh_CN

    《Hibernate 3.2.0 参考指南中文版》是Java开发人员的重要参考资料,它详细阐述了Hibernate框架在3.2.0版本中的各种功能和使用方法。Hibernate是一个开源的对象关系映射(ORM)框架,它允许开发者使用面向对象的方式...

    Hibernate_3.2.0_Reference_zh_CN.chm

    Hibernate_3.2.0_Reference_zh_CN.chm Hibernate_3.2.0_Reference_zh_CN.chm

    达梦数据库java驱动包、hibernate方言包

    * 达梦8 hibernate方言包对应版本说明 /*************************************** jar包在dialect目录下: 1. DmDialect-for-hibernate2.0.jar 对应 Jdk1.4及以上, hibernate2.0 环境 2. DmDialect-for-hibernate2.1...

    hibernate-tutorials_java_hibernate_Eclipse_fallenweg_

    总的来说,"hibernate-tutorials_java_hibernate_Eclipse_fallenweg_"这个资源包提供了一个全面的学习路径,涵盖了从安装配置到实际开发的所有关键步骤,对于希望掌握Hibernate的Java开发者来说是一份宝贵的资料。...

    hibernate方言

    `hibernatedialects.txt`可能是一个文本文件,列出了Hibernate支持的所有方言,或者详细描述了方言的用法和特性。而`com`目录可能包含了一些相关的源代码或者类库,其中可能有Hibernate的方言实现,包括...

    hibernate方言包

    hibernate方言包

    hibernate-cglib-repack-2.1_3.jar.zip

    而CGLIB则是一个代码生成库,它允许开发者在运行时动态创建子类,对Java类进行扩展。本文将详细探讨Hibernate-CGLIB的结合使用以及repack.jar在其中的作用。 首先,让我们了解Hibernate。Hibernate是一个开源的ORM...

    struts_hibernate_bbs.rar_bbs_hibernate b_hibernate bbs_struts hi

    总结来说,"struts_hibernate_bbs.rar"是一个很好的学习资源,可以帮助开发者提升在Struts和Hibernate集成应用上的技能,从而更好地构建高效、可扩展的Web应用程序,尤其是BBS类型的论坛系统。通过深入研究源代码,...

    hibernate中所有数据库方言

    ### Hibernate支持的数据库方言 在Hibernate中,为了适应不同的数据库管理系统(DBMS),它引入了“方言”(Dialect)的概念。方言是Hibernate与特定数据库进行有效沟通的关键组件,负责处理SQL语法差异,确保跨...

    Hibernate_3.2.0_Reference_zh_CN.rar

    2. 支持JPA(Java Persistence API):Hibernate 3.2.0开始全面支持JSR 220的Java Persistence API,使开发人员可以选择使用标准API,同时也提供了更丰富的功能和灵活性。 3. HQL(Hibernate Query Language)增强...

    mis.rar_MyBeanUtils _hibernate @Finder_mis_springmvc_springmvc h

    hibernate_@finder mis springmvc springmvc_hiberna" 明确了涉及的技术组件,包括MyBeanUtils(一个自定义工具类库)、Hibernate、@Finder(可能是自定义查询注解)以及两个提及的SpringMVC,暗示了SpringMVC可能有...

    DMS.rar_dms_hibernate_myeclipse hibernate_mysql hibernate_struts

    标题"DMS.rar_dms_hibernate_myeclipse hibernate_mysql hibernate_struts"表明这是一个与数据库管理系统(DMS)相关的项目,使用了Hibernate ORM框架,MyEclipse作为开发环境,并结合了MySQL数据库和Struts框架。...

    hibernate c3p0 数据库连接池参数详解.txt

    ### Hibernate C3P0 数据库连接池参数详解 在企业级应用开发中,数据库连接池技术扮演着极其重要的角色,它能显著提高系统的性能并优化资源管理。Hibernate 作为 Java 领域中最流行的 ORM(对象关系映射)框架之一...

Global site tag (gtag.js) - Google Analytics