项目中Hibernate的优化:分页

本文探讨了在项目中使用Hibernate时遇到的SQL Server分页问题,指出Hibernate默认的SQL Server方言实现是伪分页,导致性能下降。通过对Hibernate方言的扩展,实现了基于`ROW_NUMBER()`的真正分页,提高了查询效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

本文转自:http://www.iteye.com/topic/721903。

 

提到Hibernate,好多人都用“垃圾”,“效率太低”这样的字眼评价。其实任何一个框架的产生都是有原因的,这些为企业级开发产生的框架最初只是为 了简化开发,或许会有一些影响性能的地方。但是通过配置和巧妙的办法,完全可以规避这些问题,发挥最大的效果。至少目前我的项目,日均pv在500w左右 目前还没发现什么问题。
一、hibernate分页 hibernate对MsSql的伪分页
分页是web项目中比不可少的一个功能,数据量大的时候不能全部展示必然要用到分页技术。相信大家对hibernate中的分页都不陌生:

Java代码
  1. public  Query setMaxResults( int  maxResults);  
  2. public  Query setFirstResult( int  firstResult);  
public Query setMaxResults(int maxResults);
public Query setFirstResult(int firstResult);


只要调用了这两个方法并设置好参数,hibernate自动分页完全屏蔽了底层数据库分页技术,这也是众多开发者喜欢hibernate的原因之一。
项目开发中遇到一个奇怪的问题。数据库采用的是Sql Server 2005 ,也设置了上面两个参数,可是每次发送到数据库端的SQL语句都是select top ....语句。即便是查询第10w条,也只有一个select top 语句,不免引起对hibernate实现sql server分页的怀疑 。hibernate针对不同数据库实现的分页方法封装在对应数据库的方言里,通过getLimitString方法转化成对应数据库的分页算法。
以常见的Mysql数据库的方言MySQLDialect为例:

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


采用了大家熟悉的mysql的limit进行分页。
Oracle数据库的方言Oracle9iDialect:

Java代码
  1. StringBuffer pagingSelect =  new  StringBuffer( sql.length()+ 100  );  
  2.         if  (hasOffset) {  
  3.             pagingSelect.append("select * from ( select row_.*, rownum rownum_ from ( " );  
  4.         }  
  5.         else  {  
  6.             pagingSelect.append("select * from ( " );  
  7.         }  
  8.         pagingSelect.append(sql);  
  9.         if  (hasOffset) {  
  10.             pagingSelect.append(" ) row_ where rownum <= ?) where rownum_ > ?" );  
  11.         }  
  12.         else  {  
  13.             pagingSelect.append(" ) where rownum <= ?" );  
  14.         }  
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 <= ?");
		}


利用Oracle的rownum 结合三层嵌套查询完成分页。这个三层是Oracle最经典高效的分页算法。
可是针对Sql Server的方言SQLServerDialect:

Java代码
  1. public  String getLimitString(String querySelect,  int  offset,  int  limit) {  
  2.         if  ( offset >  0  ) {  
  3.             throw   new  UnsupportedOperationException(  "query result offset is not supported"  );  
  4.         }  
  5.         return   new  StringBuffer( querySelect.length() +&
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值