hibernate的分页查询

在网上找到一篇对hibernate如何实现跨数据库实现分页的文章,很受用。

链接:http://volunteer521.iteye.com/blog/908320

内容如下:

Hibernate分页,在Hibernate中通过对不同数据库的统一接口设计,实现了透明化、通用化的分页实现机制。

 

      通过Criteria.setFirstResult和Criteria.setFetchSize方法设定分页范围,如: 

Java代码   收藏代码
  1. Criteria criteria = session.createCriteria(TUser.class);  
  2. criteria.add(Expression.eq("age""20"));  //从检索结果中获取第100条记录开始的20条记录  
  3. criteria.setFirstResult(100);  
  4. criteria.setFetchSize(20);  

 

      通过Query.setFirstResult和Query.setMaxResults方法也可以设定分页范围,如: 

Java代码   收藏代码
  1. Query query = session.createQuery("from TUser");  
  2. query.setFirstResult(100);  
  3. query.setMaxResults(20);  // query.setFetchSize(20);  
  4. List list = query.list();  

 

      Hibernate中,抽象类org.hibernate.dialect.Dialect指定了所有底层数据库的对外统一接口,通过针对不同数据库提供相应的Dialect实现,数据库之间的差异性得以消除,从而为上层机制提供了透明的、数据库无关的存储层基础。对于分页机制而言,Dialect中定义了一个方法如下: 

Java代码   收藏代码
  1. /**    * Add a LIMIT clause to the given SQL SELECT    *    * @return the modified SQL    */  
  2.   public String getLimitString(String querySelect, boolean hasOffset))  
  3.   {      
  4.     throw new UnsupportedOperationException( "paged queries not supported" );   
  5.   }  
  6.   
  7.   public String getLimitString(String querySelect, int offset, int limit)  
  8.   {      
  9.     return getLimitString( querySelect, offset>0 );     
  10.   }  

 

      此方法用于在现有Select语句基础上,根据各个数据库自身特性,构造对应的记录返回限定子句。如MySQL中对应的记录限定子句为Limit,Oracle中,通过rownum子句实现。

 

      MySQLDialect中的getLimitString实现:

Java代码   收藏代码
  1. public String getLimitString(String sql, boolean hasOffset)  
  2. {      
  3.   return new StringBuffer( sql.length()+20 ).append(sql).append( hasOffset ? " limit ?, ?" : " limit ?").toString();     
  4. }  

      MySQLDialect.getLimitString方法的实现实际上是在给定的Select语句后追加MySQL所提供的专有SQL子句limit来实现。

 

      Oracle9Dialect中的getLimitString实现: 

Java代码   收藏代码
  1. public String getLimitString(String sql, boolean hasOffset)  
  2. {  
  3.   sqlsql = sql.trim();  
  4.   boolean isForUpdate = false;  
  5.   if ( sql.toLowerCase().endsWith(" for update") )  
  6.   {  
  7.     sqlsql = sql.substring( 0, sql.length()-11 );  
  8.     isForUpdate = true;  
  9.   }  
  10.     
  11.   StringBuffer pagingSelect = new StringBuffer( sql.length()+100 );  
  12.   if (hasOffset)  
  13.   {  
  14.     pagingSelect.append("select * from ( select row_.*, rownum rownum_ from ( ");  
  15.   }  
  16.   else  
  17.   {  
  18.     pagingSelect.append("select * from ( ");      
  19.   }  
  20.     
  21.   pagingSelect.append(sql);  
  22.   if (hasOffset)  
  23.   {  
  24.     pagingSelect.append(" ) row_ where rownum <= ?) where rownum_ > ?");  
  25.   }  
  26.   else  
  27.   {  
  28.     pagingSelect.append(" ) where rownum <= ?");  
  29.   }  
  30.     
  31.   if ( isForUpdate )  
  32.   {  
  33.     pagingSelect.append( " for update" );  
  34.   }  
  35.     
  36.   return pagingSelect.toString();  
  37. }  

      通过Oracle特有的rownum子句来实现数据部分的读取。

 

      SQLServerDialect中的getLimitString实现:

Java代码   收藏代码
  1. public String getLimitString(String querySelect, int offset, int limit)  
  2. {  
  3.   if ( offset > 0 )  
  4.   {  
  5.     throw new UnsupportedOperationException( "sql server has no offset" );  
  6.   }  
  7.     
  8.   return new StringBuffer( querySelect.length()+8 ).append(querySelect).insert( getAfterSelectInsertPoint(querySelect), " top " + limit ).toString();  
  9. }  

       通过SQLServer特有的top子句实现。

 

      HSQLDialect中的getLimitString实现:

Java代码   收藏代码
  1. public String getLimitString(String sql, boolean hasOffset)  
  2. {  
  3.   return new StringBuffer( sql.length() + 10 ).append( sql ).insert( sql.toLowerCase().indexOf( "select" ) + 6, hasOffset ? " limit ? ?" : " top ?" ).toString();     
  4. }  

 

      大多数主流数据库都提供了数据部分读取机制,而对于某些没有提供相应机制的数据库而言,Hibernate也通过其他途径实现了分页,如通过Scrollable ResultSet,如果JDBC不支持Scrollable ResultSet,Hibernate也会通过ResultSet的next方法进行记录定位。Hibernate通过底层对分页机制的良好封装,使得开发人员无需关心数据分页的细节实现,将数据逻辑和存储逻辑分离开来,在提高生产效率的同时,也大大加强了系统在不同数据库平台之间的可移植性。



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值