Jive中的分页处理

原创 2003年01月02日 14:10:00

在Web应用中,难免和数据库打交道,对于返回的结果集,究竟该如何处理?
尤其是,当你的一个查询可能会返回数万条纪录的时候,你还能像某些骗钱骗精力的jsp垃圾书本上介绍的用rs.next()来处理么?
呵呵,我以前就是这么干的,直接传回resultset,在jsp中while(rs.next())循环中一个
一个的处理。

还有,返回结果的分页处理的问题。很多时候我们的Web应用(或者其他)都是针对某一种数据库的(感觉商业应用绝大多数是oracle,业余的多是mysql,还敢用jdbc连接sqlServer的,估计是被M$养废了)。所以我常常会针对某些数据库的特性写一些专门的SQL语句或者存储过程来确定返回结果集的大小,以实现分页处理(其实偶是数据库白痴,除了select/insert/update,其他的不知道!)。我以前就是用伪列来实现在Oracle上处理记录结果集的分页的。

慢慢的,为了所谓的降低代码耦合度,我对查询结果集的代码进行了重构,于是稍微进步了一点,在某个queryManager之类的类中传出一个Enumeration,里边的每个对象对应了数据库中的一条纪录。嘿嘿,居然也能凑合着对付500多人使用了。
可是,这也不是最好的办法,毕竟,如果真的返回了几万条纪录,这样的处理方法不但占内存,而且效率也不搞。

记得以前在bqlr.com中看到一篇关于“查询结果返回rs,还是集合”的讨论,答案是用Iterator。
可是里边的代码很笼统,对于从未用过iterator模式的人来说,基本上没有什么可以模仿和参照的。
还好,我们有现成的,那就是Jive。
看看Jive中是怎么实现的。

(A)我们以forum.jsp这个页面为例,缺省的,每页显示15条thread,用户可以指定从第n条开始显示到n+page_size条。
代码如下:

ResultFilter filter = new ResultFilter();
filter.setStartIndex(start); //从第start条thread开始
filter.setNumResults(range); //页面大小
// Set the moderation level minimum
filter.setModerationRangeMin(forum.getModerationMinThreadValue());
 
// More forum properties
int numThreads = forum.getThreadCount(filter);
int numMessages = forum.getMessageCount(filter);
 
// Iterator of threads
ForumThreadIterator threads = forum.threads(filter); //返回thread Iterator,

 

通过分析上面代码,明确了需要重点分析ResultFilter,DBForum和ForumThreadIterator这三个类。

(B)看看ResultFilter.java
这个类其实就是专门保存查询条件的,例如,可以查询某天之前,由某人发布的贴子等。一次查询操作的所有查询条件都保存在这个类里边。
里边有一个函数比较有意思:public void setSortPropertyName(String sortPropertyName),嘿嘿可以把“是否具备某个property”作为查询条件。我本来就想给jive添加thread置顶功能,看起来只要给需要置顶的thread加一个topMost属性,然后改动skin就可以了。可谓是得来全不费工夫啊。

把查询条件填充完毕以后,就可以把resultFilter传给forum.threads()取结果了。

(C)看DBForum.threads()

    public ForumThreadIterator threads(ResultFilter resultFilter) {
 //根据传入的resultFilter构造一个查询SQL语句(*注1)
        String query = getThreadListSQL(resultFilter, false);
 //返回一个确定返回的id列表,这里缺省大小是400个,例如,我要看1~15条纪录
 // threadBlock的length是400,从1~400(*注2)
        long [] threadBlock = getBlock(query.toString(), resultFilter.getStartIndex());
        int startIndex = resultFilter.getStartIndex();
        int endIndex;
        // If number of results is set to inifinite, set endIndex to the total
        // number of threads in the forum.
        if (resultFilter.getNumResults() == ResultFilter.NULL_INT) {
            endIndex = (int)getThreadCount(resultFilter);
        }
        else {
            endIndex = resultFilter.getNumResults() + startIndex;
        }
 //嘿嘿,理解了上面几句代码先,然后来看这个iterator
        return new ForumThreadBlockIterator(threadBlock, query.toString(),
                startIndex, endIndex, this.id, factory);
    }


OK,关于(注1)
我分析了getThreadListSQL,这里是构造了一个SQL查询语句,这个语句前面的一些内容是:
SELECT jiveThread.threadID FROM jiveThread,xxxxx
那些xxxxx无非是一些查询条件,是根据resultFilter中的查询条件而自动生成的。
原来,如果执行了这个SQL的作用只能取回满足条件的thread的ID号。

(注2)getBlock()
我对这里的Block的理解是:指满足查询条件的查询结果经过排序以后的序号集合,和数据库中的threadID是不一样的。
这里的starIndex就是数组,也就是那个Block的下标,而里边的内容(Long object),是真正的threadID
代码里边对于每Block数组的大小,是固定的400。
举例来说:
如果一次查询返回1000条纪录,我要从第510条开始(startIndex=510),那么就是取第二块block(blockID=1),块起始位置(blockStart)是
500。

int blockID = startIndex / BLOCK_SIZE;
int blockStart = blockID * BLOCK_SIZE;


如果你还有耐性看到这里,并且接着读jive代码的话,会发现,加下来无非就是从Cache中取该Block数组,如果没有找到,则老老实实的从数据库中取出来,老老实实的放到数组里边,放到Cache,最后扔出这个数组。
这里的数据库处理代码比较普通

con = ConnectionManager.getConnection();
stmt = ConnectionManager.createScrollableStatement(con);
// Set the maximum number of rows to end at the end of this block.
ConnectionManager.setMaxRows(stmt, BLOCK_SIZE * (blockID+1));
ResultSet rs = stmt.executeQuery(query);
// Grab BLOCK_SIZE rows at a time.
ConnectionManager.setFetchSize(rs, BLOCK_SIZE); //一次最多取BLOCK_SIZE条,也就是400条
// Position the cursor right before the first row that we're insterested in.
ConnectionManager.scrollResultSet(rs, blockStart);// 滚动游标到blockStart
// Keep reading results until the result set is exhausted or
// we come to the end of the block.
int count = 0;
while (rs.next() && count < BLOCK_SIZE) {
  objectList.add(rs.getLong(1));
  count++;
}

 

看到这里,我忽然领悟到,这里的代码也只是复制而已,可是比我以前的复制到enumeration中要高级了好多。
首先,这里限制了jdbc返回结果集的大小。
其次,复制的内容只是一个“指针”(嘿嘿,我喜欢用这个词语)。
这样就比较好的解决了上面的速度慢和浪费内存的问题。

(C)嘿嘿,接下来的事情相对就很简单了。
1.根据startIndex计算出在该Block中的相对位置,也就是这个BlockArray中的下标啦,然后取得内容,也就是真正的threadID啦。
2.到threadCache中去取该threadObject,如果找不到,则老老实实的new thread(threadID),从数据库中去取了。
这一切都是通过ForumThreadIterator中的hasNext()/next()/getElement()来实现的。大家自己去看一下就很容易搞清楚啦。

Jsp页面简单分页处理

共${page.countrow }条记录 共${page.countpage }页 首页 上一页 5}"> ...
  • Before_Morning
  • Before_Morning
  • 2015年04月08日 21:25
  • 1113

JQuery分页处理(后端)

利用JQuery实现分页处理,首先你要了解为什么要分页。分页主要是为了避免一次性从数据库获取大量数据。其次才是为了展示效果。 关键点:要知道每页显示数,总条数 1、使用的包含文件 2、CSS文件...
  • damaolly
  • damaolly
  • 2015年06月03日 17:47
  • 3085

关于java poi导入导出excel的包冲突问题

这个问题折腾了我半天,我的导入和导出分别用了连个poi包,这两个包冲突,删掉其中一个,则另一个功能就不能使用,很纠结,试了很多方法,但是我的import的工具的版本还不能换,版本必须一致,所以我决定,...
  • liuxiaogangqq
  • liuxiaogangqq
  • 2013年12月19日 11:35
  • 3441

Python-Selenium2做Web自动化测试(11)-下拉框处理、分页处理

一、下拉框处理 下拉框也是 web 页面上非常常见的功能,要想定位下拉框中的内容,首先需要定位到下拉框;引用网友的Html文件 drop_down.html ...
  • jasonwoolf
  • jasonwoolf
  • 2015年08月09日 18:48
  • 3041

Js处理数据——前端分页工具

科技优家 2016-11-22 17:33 这几天有小伙伴讨论起了分页的相关问题,这里我也简单讲下前端如何简单便捷的利用Js(库)写出优雅,好用的分页工具。 分页是个很简单又超多接触的技术点,...
  • u011277123
  • u011277123
  • 2016年11月23日 09:47
  • 896

javaWEb中的分页处理

1.改写dao,对service 层提供分页的数据服务:getPageData()   getTotalRecord     //获取分页数据     public List getPag...
  • ldy944758217
  • ldy944758217
  • 2016年08月10日 14:33
  • 154

java web项目分页

分页主要需要三个参数:1.某个对象的总数 2.每页展示的数量  3.能分为几页 1.获取总数: select count(c.categoryId) from Category c  2.设置每页...
  • zhanghe687
  • zhanghe687
  • 2016年11月26日 20:31
  • 239

vuejs2.0实现一个简单的分页

实现的分页结果如图所示: css .page-bar{ margin:40px; } ul,li{ margin: 0px; padding: 0px; } li{ ...
  • Lucky_LXG
  • Lucky_LXG
  • 2017年03月29日 08:54
  • 4346

SpringMVC分页技术

分页是JAVA WEB项目常用的功能,昨天在Spring MVC中实现了简单的分页操作和搜索分页,在此记录一下。使用的框架为(MyBatis+SpringMVC+Spring)。      ...
  • UP19910522
  • UP19910522
  • 2014年06月12日 09:14
  • 1939

分页显示--html,js处理

效果如下: .pageJumpDiv{ display: inline-block; font-size: 14px; color: #666; position: ...
  • yu2015java
  • yu2015java
  • 2017年06月21日 15:44
  • 173
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Jive中的分页处理
举报原因:
原因补充:

(最多只允许输入30个字)