浏览 3513 次
锁定老帖子 主题:Hibernate分页源代码的疑惑?
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2008-04-18
http://www.iteye.com/topic/261也比较详细的说明过,但今天看了其中的源代码,还是不是很理解,主要是与JDBC对照而言。
谁都知道Hibernate可以实现分页查询的功能,在以前robbin的帖子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源代码上看不出特别的处理内容。 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间: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查询是把所有的记录都返回了。 |
|
返回顶楼 | |
发表时间: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记录数,然后在移动游标来实现的。实现很纳闷啊! |
|
返回顶楼 | |