Chinaunix首页 | 论坛 | 博客
  • 博客访问: 213934
  • 博文数量: 20
  • 博客积分: 3012
  • 博客等级: 中校
  • 技术积分: 502
  • 用 户 组: 普通用户
  • 注册时间: 2007-01-09 19:37
文章分类

全部博文(20)

文章存档

2011年(1)

2010年(1)

2009年(18)

我的朋友

分类: 系统运维

2009-07-16 10:14:42

 

对于Web上的数据处理,其实我是个门外汉。这样一个门外汉,为前一阵的轮讲所迫,需要解决一个经典数据库教材上的习题,这个习题,就是用完全JSP方式实现分页/翻页。

 

简单来说,比如想把查询出来的多条记录分页显示在 Web page 上,想做出这样的效果:
 
每页都有 Next 和 Previous。
 
 
 
第一页只有 Next。
 
 
 
 
最后一页只有 Previous。
 
 
 
这个看似简单的问题,解决起来其实并不算容易。百度了很多代码,也google了很多代码,分页/翻页 问题在英文里是 paging 或 pagination。
 
对于这个问题,我有三种解决方案:
 
1.最笨的:显示每一页的时候都SELECT所有数据,但是在显示的时候,只显示这页应该显示的记录。
  

//查询所有记录

rs = statement.executeQuery("SELECT * FROM books order by title, bookid");

 
    
        
   
   
       
        
    <%    
    rs.next();    
    }    
  }    
  %>    

//intLower是此页应该显示的第一条记录,intUpper是每页应该显示的最后一条记录 

<%for (i = intLower; i <= intUpper; i++){%>          
   

<%=rs.getString(1)%><%=rs.getString(2)%> <%=rs.getString(3)%><%=rs.getString(4)%>
 
 

//制作分页标签 

<%if(intLower > intPageSize){%>Previous<%}%>   
  <%if(intUpper < intCnt){%>Next<%}%>
  <%out.println((intLower / intPageSize + 1) + " of " + (intCnt / intPageSize + 1));%>

 
 
分析: 很显然,这种方法比较傻,用户翻到每页的时候,都要建立connection,浪费了大量时间;如果查询出来的记录太多,内存存不下,这种方法就失灵了。
但它是naive的,说明了分页的原理和具体操作,在记录比较少并且用户足够能忍的时候,还可以凑合用。
 
 
 
2.稍好的:对于每一页,只查询一半记录,这一半记录包含了此页需要显示的记录。
 

//如果用户是点了 Previous 进入这一页的:strFirstTitle 和 intFirstBookid 是父页的第一条记录的标志,用它来做条件查询,只SELECT 这条记录之前的所有记录,再从这些 SELECT 出的记录中截取此页应该显示的记录。

rs = statement.executeQuery("SELECT * FROM books WHERE (title = '" + strFirstTitle + "'AND bookid <" + intFirstBookid + " ) OR (title <'" + strFirstTitle + "') ORDER BY title, bookid");

 
 

//如果用户是点了 Next 进入这一页的: strLastTitle 和 intLastBookid 是父页最后一条记录的标志,用它来做条件查询,只SELECT这条记录之后的所有记录,再从这些 SELECT 出的记录中截取此页应该显示的记录。

rs = statement.executeQuery("SELECT * FROM books WHERE (title = '" + strLastTitle + "'AND bookid >" + intLastBookid + " ) OR (title >'" + strLastTitle + "') ORDER BY title, bookid");

    
          
     
     
         
          
    <%
      i++;    
    }while ((rs.next()) && (i < intPageSize));    
    %> 

//用DO...WHILE循环把截取的记录显示一下。   

   <%do {
    %>    
     

<%=rs.getString(1)%><%=rs.getString(2)%> <%=rs.getString(3)%><%=rs.getString(4)%>

//在此页的下部,做成 Next 和 Previous 按钮,并把改传的标志数据传给子页。  

    <%
    if(intPage > 1)
    {
    %>
      Previous
    <%
    }//if
    %>   
    <%
    if(intPage < (intCnt / intPageSize + 1) )
    {
    %>
      Next
    <%
    }//if
    %>   
  <%
  }//if
  %>
  <%out.println(intPage + " of " + (intCnt / intPageSize + 1));%>

分析:这种方法一定程度上解决了“如果结果集太大,内存可能不够”的问题。但却不是“想显示多少,就 SELECT 多少”的。而且显示每一页的时候都要重复建立 connection ,花费大量时间,在这方面,跟第一种方法的缺点一样。

3. 比较好的:对于每一页,想显示多少,就 SELECT 多少。运用排序和 LIMIT 选择 topn 的记录。

//如果用户是点了 Previous 进入这一页的:还是用父页的第一条记录做标志,向前 SELECT 每页想显示的记录数,然后再把它们反序。 

rs = statement.executeQuery("SELECT * FROM (SELECT * FROM books WHERE (title = '" + strFirstTitle + "'AND bookid <" + intFirstBookid + " ) OR (title <'" + strFirstTitle + "') ORDER BY title desc, bookid desc LIMIT " + 0 + " ," + intPageSize + " ) AS temptable ORDER BY title asc, bookid asc");

//如果用户是点了 Next 进入这一页的:还是用父页的最后一条记录做标志,向后 SELECT 每页向现实的记录数。

rs = statement.executeQuery("SELECT * FROM books WHERE (title = '" + strLastTitle + "'AND bookid >" + intLastBookid + " ) OR (title >'" + strLastTitle + "') ORDER BY title, bookid LIMIT " + 0 + " ," + (intPageSize + 1));

    
          
     
     
         
          
    <%
      i++;    
    }while ((rs.next()) && (i < intPageSize));    
    %>    
   

//做个DO...WHILE循环,把此页的记录显示在Web Page上。   

    <%do {
    %>    
     

<%=rs.getString(1)%><%=rs.getString(2)%> <%=rs.getString(3)%><%=rs.getString(4)%>
    

//在此页下方显示 Next 和 Previous 按钮,并把需要的数据传给子页。

    <%
    if(intPage > 1)
    {
    %>
      Previous
    <%
    }//if
    %>   
    <%
    if(intLastPage != 1)
    {
    %>
      Next
    <%
    }//if
    %>   
  <%
  }//if
  %>

分析: 这种方法实现了“想显示多少条,就 SELECT 多少条”的目的。但是对于每页,仍然是重复建立 connection。对于 Web 应用我实在是个门外汉,如果是纯 JSP 解决方案,我只能做到这个程度了。sigh~

 

 

关于这个问题的讨论,以下文章写得很好很详细,全面讨论了 cache-based 和 query-based 的解决方案:

Paging in J2EE: Manage Large Result Sets Efficiently

写得实在太好,本来想翻译一下的,可是正是因为作者写得太好,所以不敢贸然翻译,生怕贻笑大方。只得贴在这里让大家欣赏下原文了。

 

 

关于这个问题的 research,是轮讲的时候做的,所以自己弄了ppt,传上来给大家看看,以弥补语言表达上的不足。

文件: ex7.6.pdf
大小: 780KB
下载: 下载
阅读(910) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~