JDBC分页工具类

fmms 12年前
     <p class="MsoNormal"><span>不知道大家做项目做到最后有什么感觉没有,其实大家做来做去就是做一个列表加上分页和多条件的查询,只是不同的项目业务流程不一样而已,所以今天我想说说这里的分页。</span></p>    <p class="MsoListParagraph"><span lang="EN-US">1、<span style="line-height:normal;font-variant:normal;font-style:normal;font-size:7pt;font-weight:normal;"> </span></span><span>大家需要了解的是为什么我们需要分页?</span></p>    <p style="text-indent:0cm;margin-left:18pt;" class="MsoListParagraph"><span>因为当数据量太大时,会影响查询和传输的性能,并且我们从用户角度来考虑的话,如果让用户一次性看到成千上万条记录那用户也会疯掉的。</span></p>    <p class="MsoListParagraph"><span lang="EN-US">2、<span style="line-height:normal;font-variant:normal;font-style:normal;font-size:7pt;font-weight:normal;"> </span></span><span>对我们来说有哪些可实现的分页技术?</span></p>    <p class="MsoListParagraph"><span lang="EN-US">a、<span style="line-height:normal;font-variant:normal;font-style:normal;font-size:7pt;font-weight:normal;"> </span></span><span>存储过程分页,即在数据库中创建一个存储过程,传入<span lang="EN-US">SQL</span>和页码获取当前页的记录,这个需要大家对存储过程有比较好的认识(我这块不行),当然这个从性能上来说是最好的,但是不能跨数据库平台。</span></p>    <p class="MsoListParagraph"><span lang="EN-US">b、<span style="line-height:normal;font-variant:normal;font-style:normal;font-size:7pt;font-weight:normal;"> </span></span><span>使用数据库专有<span lang="EN-US">SQL</span>语句进行分页(<span lang="EN-US">Oracle</span>的<span lang="EN-US">rownum</span>、<span lang="EN-US">MSSQL</span>的<span lang="EN-US">top</span>、<span lang="EN-US">MySql</span>的<span lang="EN-US">limit</span>等),性能也很好,但是还是不能跨数据库(其实真实项目中没那么多项目要求都跨数据库)。</span></p>    <p class="MsoListParagraph"><span lang="EN-US">c、<span style="line-height:normal;font-variant:normal;font-style:normal;font-size:7pt;font-weight:normal;"> J</span></span><span lang="EN-US">DBC</span><span>分页,通过<span lang="EN-US">Statement</span>的<span lang="EN-US">statement.setMaxRow(endIndex)</span>和<span lang="EN-US">resultSet.absoulte(beginIndex)</span>取得当前页范围内的记录。此种方式的性能依赖于厂商对<span lang="EN-US">JDBC</span>规范的实现。这种方式的通用性是最好的,性能也不错,完全与数据库平台无关了。</span></p>    <p class="MsoListParagraph"><span lang="EN-US">d、<span style="line-height:normal;font-variant:normal;font-style:normal;font-size:7pt;font-weight:normal;"> </span></span><span>根据数据库类型自动生成数据库专有特性的<span lang="EN-US">sql</span>语句,其实说白了也就是<span lang="EN-US">Hibernate</span>的实现方式,这个自己也写过一个,其实就是根据数据库类型生成不同的数据库<span lang="EN-US">SQL</span>专有语句而已。</span></p>    <p class="MsoNormal"><span lang="EN-US"> </span></p>    <p class="MsoNormal"><span>下面我们需要写一个分页工具类,在写之前我们需要弄明白分页的原理。为了能够取得指定页码所对应的记录,我们是不是需要两个关键的参数:总记录数和每页的记录数;</span></p>    <p class="MsoNormal"><span>每页的记录数我们可以设置一个默认值,<span lang="EN-US">10</span>、<span lang="EN-US">15</span>、<span lang="EN-US">20</span>、<span lang="EN-US">25</span>都无所谓,根据实际需求。</span></p>    <p class="MsoNormal"><span>总记录数就没办法了,需要额外从数据库中利用<span lang="EN-US">Count</span>函数取了,通过这两个参数我们是不是可以计算出总页数。同时我们也可以判断用户传过来的页码是否有效(小于第一页<span lang="EN-US">OR</span>超出最后一页),然后我们再根据页码和每页记录数是不是就可以计算出当前页的的开始条数和终止条数了。</span></p>    <p class="MsoNormal"> </p>    <p class="MsoNormal"><span>下面我们就需要来看看分页的工具类了</span></p>    <pre class="brush:java; toolbar: true; auto-links: false;">package com.iflytek.page;  /**  * 分页工具类  *   * @author xudongwang 2012-1-19  *   *         Email:xdwangiflytek@gmail.com  */ public class Page {   /**   * 总记录数   */  private int totalRow;   /**   * 每页记录数   */  private int pageSize = 10;   /**   * 当前页码   */  private int currentCount;   /**   * 总页数   */  private int total;   /**   * 起始记录下标   */  private int beginIndex;   /**   * 截止记录下标   */  private int endIndex;   /**   * 构造方法,使用总记录数,当前页码   *    * @param totalRow   *            总记录数   * @param currentCount   *            当前页面,从1开始   */  public Page(int totalRow, int currentCount) {   this.totalRow = totalRow;   this.currentCount = currentCount;   calculate();  }   /**   * 构造方法 ,利用总记录数,当前页面   *    * @param totalRow   *            总记录数   * @param currentCount   *            当前页面   * @param pageSize   *            默认10条   */  public Page(int totalRow, int currentCount, int pageSize) {   this.totalRow = totalRow;   this.currentCount = currentCount;   this.pageSize = pageSize;   calculate();  }   private void calculate() {   total = totalRow / pageSize + ((totalRow % pageSize) > 0 ? 1 : 0);    if (currentCount > total) {    currentCount = total;   } else if (currentCount < 1) {    currentCount = 1;   }    beginIndex = (currentCount - 1) * pageSize;   endIndex = beginIndex + pageSize;   if (endIndex > totalRow) {    endIndex = totalRow;   }  }   public int getTotalRow() {   return totalRow;  }   public int getPageSize() {   return pageSize;  }   public int getCurrentCount() {   return currentCount;  }   public int getTotal() {   return total;  }   public int getBeginIndex() {   return beginIndex;  }   public int getEndIndex() {   return endIndex;  }  }</pre>    <p></p>    <p> <span>继续</span></p>    <p><span style="font-size:10.5pt;">在后台获取前台传进来的页码</span><span style="background-color:#fafafa;white-space:pre;"> //从页面取得页码 </span></p>    <pre class="brush:java; toolbar: true; auto-links: false;">    int currentPage = 1;       try {        currentPage = Integer.parseInt(request.getParameter("currentPage"));       } catch (Exception ex) {}              //取得总记录数,创建Page对象       int totalRow = studentDao.getAllStudents();//通过select count 取得总记录数       Page page = new Page(totalRow, currentPage);       studentDao.list(page);  </pre>数据访问层,    <span>StduentDao.java<pre class="brush:java; toolbar: true; auto-links: false;">public List<Stduent> getStudentsByPage(Page page) {           List<Stduent> students = new ArrayList<Stduent>();           try {               String sql = "SELECT id,name,email FROM tbl_stduent";               Connection conn = null;               try {                   conn = DbUtil.getConnection();                   Statement statement = conn.createStatement();                   statement.setMaxRows(page.getEndIndex());//关键代码,设置最大记录数为当前页记录的截止下标                   ResultSet resultSet = statement.executeQuery(sql);                   if (page.getBeginIndex() > 0) {                    resultSet.absolute(page.getBeginIndex());//关键代码,直接移动游标为当前页起始记录处                   }                   while (resultSet.next()) {                       Stduent student = new Student();                       ……                       students.add(student);                   }                   resultSet.close();                   statement.close();               } finally {                   if (conn != null) {                       conn.close();                   }               }           } catch (SQLException e) {               e.printStackTrace();           }           return students;       }  </pre></span>    <span>其实仔细想想</span>    <span lang="EN-US">JDBC</span>    <span>分页的性能与页码有关即与</span>    <span lang="EN-US">statement.setMaxRows</span>    <span>有效,越往后翻,性能越差,因为越往后一次性查询的记录数就多,但是我们从用户的角度来看不会有用户会牛逼的一页一页翻到第</span>    <span lang="EN-US">n</span>    <span>页去,一般都是根据条件来缩小查询范围。所以折中的办法就是将记录数设大一点,另外就是限制用户翻页的范围,其实这些性能的前提都是在数据量非常大的情况下而言的,一般数据量少的话,基本上都可以忽略不计的。<br /> 来自:<a href="/misc/goto?guid=4959517411811914265" target="_blank">http://xdwangiflytek.iteye.com/blog/1358080</a><br /> </span>    <p></p>