分页在任何系统中都是非常头疼的事情,有的数据库在语法上支持分页,而有的数据库则需要使用可滚动游标来实现,并且在不支持可滚动游标的系统上只能使用单向游标逐步接近要取得的数据。
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分页查询小结
hibernate分页Hibernate 分页的设计和编码
hibernate分页查询 数据库连接,不错的分析,可以尝试下载易用。。
Hibernate分页查询原理解读 , 忘记以前在哪看的了, 现在贴出来和大家分享一下。
hibernate分页(无排序,搜索,仅仅分页显示),服务器端分页在datatables上展现,有关 datatables的知识请关注它的官网http://www.datatables.net/,datatables的功能很 全面。 2,建表的sql--studentinfo和插入...
STRUTS2+HIBERNATE分页 实现代码详细的分页实现代码实现代码详细的分页实现代码实现代码详细的分页实现代码实现代码详细的分页实现代码
hibernate分页查询,里面包含数据库。自己写的。能正常运行。
传统的网页设计只在一个JSP或者ASP页面中书写所有关于数据库操作的代码,那样做分页可能简单一点,但当把网站分层开发后,分页就比较困难了,下面是我做Spring+Hibernate+Struts2项目时设计的分页代码,与大家分享...
hibernate分页代码,直接能在myeclipse上运行的好东西
spring+hibernate 分页 +mysql 可以当做模板用。
hibernate分页 博文链接:https://iomo.iteye.com/blog/243518
java 实现的一个简单的hibernate分页类 可以设置,从某一条开始取、显示的条数 不依赖struts spring
Hibernate分页
Struts+Hibernate分页标签 Struts+Hibernate分页标签
Hibernate分页教学视频 Hibernate分页教学视频 Hibernate分页教学视频
这是一个类,可以通用,只要传入两个参数即可,一个是...Query query是hibernate中session创建的query;字符char ch代表操作:‘a’就是all全部,'n'就是next下一页,'u'就是up上一页;'e'就是end末页,'s'就是start首页
Struts2+Sprint+Hibernate分页查询功能,实现过程步骤完整。
Hibernate分页可能引起的性能问题 在使用Hibernate进行分页的过程中,如果你收到如下警告,那么这里就是一个潜在的性能问题点: WARNING: firstResult/maxResults specified with collection fetch; applying in ...