论坛首页 Java企业应用论坛

Hibernate分页源代码的疑惑?

浏览 3513 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2008-04-18  
谁都知道Hibernate可以实现分页查询的功能,在以前robbin的帖子http://www.iteye.com/topic/261也比较详细的说明过,但今天看了其中的源代码,还是不是很理解,主要是与JDBC对照而言。

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


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

实际上返回的sql语句大体机构是
select top 799990 字段名 from 表名 where 条件

所以在PreparedStatement执行的sql语句是选取前面的799990条记录给结果集ResultSet

下面的方法定义了游标是否能够移动:如果支持scrollable result,使用ResultSet的absolute方法直接移到查询起点,如果不支持的话,使用循环语句,rs.next一点点的移过去。
private void advance(final ResultSet rs, final RowSelection selection) throws SQLException {
    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();
	    }
        }
}

上面的方法说明了先将结果集的位置确定好,然后在用下面的方法封装获取的分页结果集封装成集合返回
final List results = new ArrayList();
for ( count = 0; count < maxRows && rs.next(); count++ ) {
    if ( log.isTraceEnabled() ) log.debug("result set row: " + count);
	Object result = getRowFromResultSet( rs,session,queryParameters,lockModeArray,
			optionalObjectKey,hydratedObjects,keys,returnProxies 
);
results.add( result );

自此Hibernate分页完成.

下面就是我的疑惑问题了:
[b][/b]
1、Hibernate中的ResultSet为什么在返回结果集很大的情况下,依然能正常应用,而同样用JDBC查询同样数目的记录集可能发生OutOfMemory异常?
2、从Hibernate显示的分页语句也是取前面N(top)条语句,Hibernate是否进行过其他处理,但从Hibernate源代码上看不出特别的处理内容。
   发表时间:2008-04-18  
其实你根本没明白Hibernate分页是怎么回事情。
之所以会有select top 出现,是因为SQL Server2000自己不支持rowid。这是sql server2000专有的。你看看hibernate生成的oracle语句,根本就没有top。
hibernate根据hql生成sql的时候,需要根据不同数据库方言生成符合该数据库sql标准的语句。如果数据库支持rowid,那么优先使用rowid,然后是top方式,最后是用游标移过去。
Hibernate中的ResultSet为什么在返回结果集很大的情况下,依然能正常应用,而同样用JDBC查询同样数目的记录集可能发生OutOfMemory异常?
这是因为返回的只有记录的主键。你自己jdbc查询是把所有的记录都返回了。
0 请登录后投票
   发表时间:2008-04-20  
我也知道在Hibernate中的分页SQL语句采用了不同的写法,比如Oracle中的rowid,MySql中的limit以及MS SQL中的top等,我其实到Hibernate的源代码总看过,我觉得它的查询方法和JDBC没有什么区别(也许我没有看出来),所以才有这个疑问啊。
以MS SQL数据库为例:
Hibernate查询是先获取一个select top语句
if ( useLimit ) {
    sql = dialect.getLimitString( 
         sql.trim(), //use of trim() here is ugly?
	 useOffset ? getFirstRow(selection) : 0, 
	 getMaxOrLimit(selection, dialect) 
    );
}
sql = preprocessSQL( sql, queryParameters, dialect );



然会在org.Hibernate.loader.Loader类调用执行SQL的语句
final PreparedStatement st = prepareQueryStatement( queryParameters, false, session );
final ResultSet rs = getResultSet( st, queryParameters.hasAutoDiscoverScalarTypes(),
queryParameters.isCallable(), 
selection, session );

上面的getResultSet方法其实调用的是下面的内容
public ResultSet getResultSet(PreparedStatement ps) throws SQLException {
    //执行select top语句,返回结果集
    ResultSet rs = ps.executeQuery();
    //在这里可以取处结果集中任何记录字段值,大家可以试一试!
    resultSetsToClose.add(rs);
    logOpenResults();
    return rs;
}

从上可知也是JDBC的查询方法啊!

楼上说的是,在结果集中ResultSet中只存放着标识键或主键,那卫生么我也能在ResultSet rs = ps.executeQuery();的下面取出所有的结果集中的内容,当然你说的标识键(主键除外)。因此我才有疑问为什么在JDBC中查询能内存用光,而在Hibernate中查询中却不会发生这种现象。针对MS SQL的分页SQL语句采用的是选取top记录数,然后在移动游标来实现的。实现很纳闷啊!
1 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics