发帖    主题    评论    推荐    标签    作者    订阅    查搜    注册   登陆   关注
 
面向对象 设计模式 领域驱动设计 企业架构 框架 开发教程 微服务 CQRS 扩展性 并发编程 事件溯源 分布式 SOA
1 2 3 4 ... 5 下一页 Go 5

Hibernate实现分页查询的原理

         
2003-09-10 20:02
赞助商链接

在前面几个帖子的讨论过程中,我为了搞清楚问题,查了一下Hibernate源代码,搞清楚了Hibernate分页查询的原理,介绍一下:

Hibernate List可以实现分页查询:
从第2万条开始取出100条记录

Query q = session.createQuery("from Cat as c");
q.setFirstResult(20000);
q.setMaxResults(100);
List l = q.list();


那么Hibernate底层如何实现分页的呢?实际上Hibernate的查询定义在net.sf.hibernate.loader.Loader这个类里面,仔细阅读该类代码,就可以把问题彻底搞清楚。

Hibernate2.0.3的Loader源代码第480行以下:

if (useLimit) sql = dialect.getLimitString(sql);
PreparedStatement st = session.getBatcher().prepareQueryStatement(sql, scrollable);


如果相应的数据库定义了限定查询记录的sql语句,那么直接使用特定数据库的sql语句。

然后来看net.sf.hibernate.dialect.MySQLDialect:

public boolean supportsLimit() {
return true;
}
public String getLimitString(String sql) {
StringBuffer pagingSelect = new StringBuffer(100);
pagingSelect.append(sql);
pagingSelect.append(" limit ?, ?");
return pagingSelect.toString();
}

这是MySQL的专用分页语句,再来看net.sf.hibernate.dialect.Oracle9Dialect:

public boolean supportsLimit() {
return true;
}

public String getLimitString(String sql) {
StringBuffer pagingSelect = new StringBuffer(100);
pagingSelect.append("select * from ( select row_.*, rownum rownum_ from ( ");
pagingSelect.append(sql);
pagingSelect.append(
" ) row_ where rownum <= ?) where rownum_ > ?");
return pagingSelect.toString();
}

Oracle采用嵌套3层的查询语句结合rownum来实现分页,这在Oracle上是最快的方式,如果只是一层或者两层的查询语句的rownum不能支持order by。

除此之外,Interbase,PostgreSQL,HSQL也支持分页的sql语句,在相应的Dialect里面,大家自行参考。

如果数据库不支持分页的SQL语句,如果在配置文件里面
#hibernate.jdbc.use_scrollable_resultset true
默认是true,如果你不指定为false,那么Hibernate会使用JDBC2.0的scrollable result来实现分页,看Loader第430行以下:


if ( session.getFactory().useScrollableResultSets() ) {
// 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();
}


如果支持scrollable result,使用ResultSet的absolute方法直接移到查询起点,如果不支持的话,使用循环语句,rs.next一点点的移过去。

值得一提的是,Oracle的JDBC驱动的Scrollable ResultSet的实现方法实际上也是用循环语句rs.next一点点的移过去。



2
2003-09-10 20:31

不过Oracle的absolute还不算如何丑陋,最丑陋的是MySQL。 MySQL是把所有的记录一股脑取到内存,你要其中几条,它就返回给你几条。

2003-09-10 20:47

Hibernate的Dialect还是做的比较好,
以前我们在oracle都是用嵌套3层的sql来做分页的, 不用遍历ResultSet
oracle嵌套2层也是可以的, 但开销大一点
SELECT * from (
select rownum , rsisql_alias.*, rank() over (order by rownum) rsisql_rownum from (

select * from reporter.queue
) rsisql_alias ) where rsisql_rownum > 10
and rsisql_rownum <= 20

2003-09-10 21:29

看来使用Hibernate的HQL有一个好处,增强了平台的兼容性,不必象直接使用JDBC一样,为了数据库平台通用性丧失一些性能了。

我一直在找一段语法:就是只返回ID或一个字段,不返回一个Java Object的Query做法?

2003-09-10 21:48


Query q = session.createQuery("select c.id, c.name from Cat as c");
List l = q.list();
Object[] row = new Object[2];
for (i=0; i< l.size(); i++) {
row = l.get(i);
Integer id = (Integer) row[0];
String name = (String) row[1];
System.out.println(id+
" "+name);
}



5Go 1 2 3 4 ... 5 下一页

赞助商链接

赞助商链接

返回顶部

移动版 关于本站 使用帮助 联系反馈 最佳分辨率1366x768
OpenSource JIVEJDON Powered by JdonFramework Code © 2002-20 jdon.com