基于JDBC的通用分页实现

本文探讨了数据量过大时采用分页技术的原因,并介绍了几种常见的分页实现方式,包括存储过程分页、数据库专有SQL特性分页、纯JDBC分页及根据数据库类型自动生成SQL语句分页。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

分页是一个被讲到烂掉的话题,今天我再拾起来踹几脚吧 
(Hibernate的分页做得很好很强大,用的人都知道 基于JDBC的通用分页实现 - 北一止水 -  ,这个就不用再说了) 
1.为什么要分页? 
   首先是数据量太大会影响查询和传输的性能,关键是对用户来说一下看到数万条记录也不是那么友好。 
2.有哪些分页技术? 
a)存储过程分页 
   在数据库中创建一个存储过程,传入SQL和页码获得当前页的记录。需要对具体数据库的语法相当熟悉才能够编写,当然也可以直接google。性能最好,但不跨数据库平台。 
b)数据库专有sql特性分页 
   使用数据库专有的特性(MSSQL的top、Oracle的rownum、MySQL的limit等)实现当前页记录提取。性能也非常好,但也不跨数据库平台。 
(为什么非要跨数据库平台呢?好吧,如果你的项目确定是不会换数据库的那就这么写吧。) 
c)纯JDBC分页 
   通过Statement的setMaxRow(endIndex)和rs.absoulte(beginIndex)仅取得当前页范围内的记录。此种方式的性能依赖于厂商对JDBC规范的实现,如果厂商的rs读取是以流的形式进行的,性能还是有所保障的(好吧我承认是这不负责的说法)。这种方式的通用性是最好的,完全与数据库平台无关了(牺牲性能换取跨平台特性是Java平台的常用手法,嘿嘿嘿)。 
d)根据数据库类型自动生成数据库专有特性的sql语句   
   其实这就是Hibernate的实现方法,如果你觉得自己分析SQL语法然后将SQL转换为特定数据库语法比较麻烦,那就用Hibernate吧。如果你不想用Hibernate还是想用这种方法,那就麻烦你多辛苦一点,用力写出来给大家分享吧。 

我们来理一理分页的逻辑吧 
首先,对用户而言他是不关心你是怎么分页的,他只要给你一个页码,然后你把那一页的记录给他就行了。 
为了能够取得指定页码所对应的记录,我们还需要两个关键的参数:每页记录数、总记录数。 
   每页记录数可以设个默认值,20、30都行吧。 
   总记录数就需要额外从数据库中取得了,这个也是没办法的事,谁让ResultSet没提供获取记录总数的方法呢。 
通过这两个参数能够计算出来总页数,同时也就可以判断用户给出的页码是否有效了(超出最后一页或者小于第一页),然后根据页码和每页记录数就可以算出来当前页的记录起止范围了。(这些个算术都是小学的,就不用说了吧,其实我也是想了半天的) 
为了表示方便,就把这些参数写成一个类,同时把计算方法也写进去 

Java代码    收藏代码
  1.   
  2. public class Page  
  3.     private int rowTotal;// 总记录数  
  4.     private int pageSize 10;// 每页记录数  
  5.   
  6.     private int count;// 当前页码  
  7.       
  8.     private int total;// 总页数  
  9.     private int beginIndex;//起始记录下标  
  10.     private int endIndex;//截止记录下标  
  11.   
  12.       
  13.     public Page(int totalRow, int count)  
  14.         this.rowTotal totalRow;  
  15.         this.count count;  
  16.         calculate();  
  17.      
  18.   
  19.       
  20.     public Page(int totalRow, int count, int pageSize)  
  21.         this.rowTotal totalRow;  
  22.         this.count count;  
  23.         this.pageSize pageSize;  
  24.         calculate();  
  25.      
  26.   
  27.     private void calculate()  
  28.         total rowTotal pageSize ((rowTotal pageSize) 0 1 0);  
  29.   
  30.         if (count total)  
  31.             count total;  
  32.         else if (count 1 
  33.             count 1 
  34.          
  35.   
  36.         beginIndex (count 1pageSize  
  37.         endIndex beginIndex pageSize  
  38.         if (endIndex rowTotal)  
  39.             endIndex rowTotal;  
  40.          
  41.      
1)该分页组件不依赖任何底层数据库实现,可以根据需要扩展子类进行动态替换;2)同时也不提供页面如何显示上页,下页等;内部提供了源代码实现,以及DEMO应用,实现分页非常简单;<br/>需要做的工作有三个地方<br/>1.继承实现分页的抽象类AbstractPage 的两个抽象方法;<br/>2.调用WebPageUtils.doAction方法传入参数即可<br/>3.直接获取需要满足条件的记录<br/><br/><br/>下面举了一个例子来说明使用方法:<br/><br/>package org.hgg.hq.test;<br/><br/>import java.util.ArrayList;<br/>import java.util.List;<br/><br/>import javax.servlet.http.HttpServletRequest;<br/>import javax.servlet.http.HttpServletRequestWrapper;<br/><br/><br/>import org.hqq.hq.impl.AbstractPage;<br/>import org.hqq.hq.impl.ActionTypes;<br/>import org.hqq.hq.impl.WebPageUtils;<br/><br/><br/>public class DemoPage extends AbstractPage {<br/>//根据要求返回从startRow开始的rowCount条记录,可以使用其他组件来实现或者 JDBC实现都可以<br/>protected List acPageData(int startRow, int rowCount) {<br/>List data=new ArrayList();<br/>//4*2四行二列<br/>String[][] rows={{"1","A"},{"2","B"},{"3","C"},{"4","D"}};<br/>for(int i=1;i<=rowCount&&i<=acTotalRows();i++){<br/>data.add(rows[startRow++]);<br/>}<br/>return data;<br/>}<br/>//返回满足条件的总记录条数<br/>protected int acTotalRows() {<br/><br/>return 4;<br/>}<br/><br/>public static void main(String[] args) {<br/><br/>//1.0得到一个实现的实例<br/>DemoPage page=new DemoPage();<br/>//2.0如果有必要,设置每页显示大小,这里设置每页显示3条记录<br/>page.setPageSize(3);<br/>//3.0 根据需要进行必要设置,这里是显示第2页数据<br/>//根据情况,该方法后面两个参数可以从request中获取<br/>WebPageUtils.doAction(page, ActionTypes.GO_SPECIAL_PAGE,2);<br/>//4.0获取当前页数据<br/>List data=page.getCurrentPageData();<br/><br/>for(Object t:data){<br/>System.out.println(((String[])t)[0]+" : "+((String[])t)[1]);<br/>}<br/><br/>}<br/><br/>}<br/><br/>如果是WEB页面上的分页可以直接使用<br/>List data=WebPageUtils.acPageData(request,DemoPage.class);<br/>就可以得到数据了,其中request中存放了ActionTypes中定义的各个动作;<br/>例如<br/><\% String first= request.getContextPath()+"/fwgl/fycx.do?"+WebPageUtils.ACTION_TYPE+"="+ActionTypes.GO_FIRST_PAGE;<br/>String next= request.getContextPath()+"/fwgl/fycx.do?"+WebPageUtils.ACTION_TYPE+"="+ActionTypes.GO_NEXT_PAGE;<br/><br/>%\><br/>\< \a href="javascript:window.location.href='<\%=first%\>'" class="List_operatelink"\>首页\<br/>\<\a href="javascript:window.location.href='<\%=next%\>'" class="List_operatelink"\>下页\<br/><br/><br/>页面上的显示实现不用做任何分页逻辑,只需简单定义 首页 上页 下页 到 页 即可,他们都在ActionTypes中定义。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值