Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1942206
  • 博文数量: 219
  • 博客积分: 8963
  • 博客等级: 中将
  • 技术积分: 2125
  • 用 户 组: 普通用户
  • 注册时间: 2005-10-19 12:48
个人简介

文章分类

全部博文(219)

文章存档

2021年(1)

2020年(3)

2015年(4)

2014年(5)

2012年(7)

2011年(37)

2010年(40)

2009年(22)

2008年(17)

2007年(48)

2006年(31)

2005年(4)

分类: Java

2006-03-03 19:17:50

 

  目前比较广泛使用的分页方式是将查询结果缓存在HttpSession或有状态bean中,翻页的时候从缓存中取出一页数据显示。这种方法有两个主要的缺点:一是用户可能看到的是过期数据;二是如果数据量非常大时第一次查询遍历结果集会耗费很长时间,并且缓存的数据也会占用大量内存,效率明显下降。

  其它常见的方法还有每次翻页都查询一次数据库,从ResultSet中只取出一页数据(使用rs.last();rs.getRow()获得总计录条数,使用rs.absolute()定位到本页起始记录)。这种方式在某些数据库(如oracle)的JDBC实现中差不多也是需要遍历所有记录,实验证明在记录数很大时速度非常慢。

  至于缓存结果集ResultSet的方法则完全是一种错误的做法。因为ResultSet在Statement或Connection关闭时也会被关闭,如果要使ResultSet有效势必长时间占用数据库连接。

  因此比较好的分页做法应该是每次翻页的时候只从数据库里检索页面大小的块区的数据。这样虽然每次翻页都需要查询数据库,但查询出的记录数很少,网络传输数据量不大,如果使用连接池更可以略过最耗时的建立数据库连接过程。而在数据库端有各种成熟的优化技术用于提高查询速度,比在应用服务器层做缓存有效多了。

  在oracle数据库中查询结果的行号使用伪列ROWNUM表示(从1开始)。例如select * from employee where rownum<10 返回前10条记录。但因为rownum是在查询之后排序之前赋值的,所以查询employee按birthday排序的第100到120条记录应该这么写:

[pre]        select * from (

            select my_table.*, rownum as my_rownum from (

                select name, birthday from employee order by birthday

            ) my_table where rownum <120

        ) where my_rownum>=100

[/pre]

  mySQL可以使用LIMIT子句:

    select name, birthday from employee order by birthday LIMIT 99,20

  DB2有rownumber()函数用于获取当前行数。

  SQL Server没研究过,可以参考这篇文章:http://www.csdn.net/develop/article/18/18627.shtm

  在Web程序中分页会被频繁使用,但分页的实现细节却是编程过程中比较麻烦的事情。大多分页显示的查询操作都同时需要处理复杂的多重查询条件,sql语句需要动态拼接组成,再加上分页需要的记录定位、总记录条数查询以及查询结果的遍历、封装和显示,程序会变得很复杂并且难以理解。因此需要一些工具类简化分页代码,使程序员专注于业务逻辑部分。下面是我设计的两个工具类:

  PagedStatement  封装了数据库连接、总记录数查询、分页查询、结果数据封装和关闭数据库连接等操作,并使用了PreparedStatement支持动态设置参数。

  RowSetPage  参考PetStore的page by page iterator模式, 设计RowSetPage用于封装查询结果(使用OracleCachedRowSet缓存查询出的一页数据,关于使用CachedRowSet封装数据库查询结果请参考)以及当前页码、总记录条数、当前记录数等信息, 并且可以生成简单的HTML分页代码。

  PagedStatement 查询的结果封装成RowsetPage。

  下面是简单的使用示例

  1.     //DAO查询数据部分代码:
  2.     …
  3.     public RowSetPage getEmployee( gender, int pageNo) throws{
  4.          sql="select emp_id, emp_code,  user_name, real_name from employee where gender =?";
  5.        //使用Oracle数据库的分页查询实现,每页显示5条
  6.         PagedStatement pst =new PagedStatementOracleImpl(sql,  pageNo, 5);
  7.         pst.setString(1, gender);
  8.         return pst.executeQuery();
  9.     }
  10.     //Servlet处理查询请求部分代码:
  11.     …
  12.     int pageNo;
  13.     try{
  14.         //可以通过参数pageno获得用户选择的页码
  15.         pageNo = .parseInt(request.getParameter("pageno") );
  16.     }catch( ex){
  17.         //默认为第一页
  18.         pageNo=1;
  19.     }
  20.      gender = request.getParameter("gender" );
  21.     request.setAttribute("empPage", myBean.getEmployee(gender, pageNo) );
  22.     …
  23.     //JSP显示部分代码
  24. <%@ page import = "page.RowSetPage"%>
  25.     …
  26.     "javascript">
  27.         function doQuery(){
  28.             form1.actionType.value="doQuery";
  29.             form1.submit();
  30.     }
  31.     
  32.     …
  33.     
  34.       
  35.       性别:
  36.       "<%=request.getParameter("gender")%>">
  37.       " 查询 " onclick="doQuery()">
  38. <%
  39.     RowSetPage empPage = (RowSetPage)request.getAttribute("empPage");
  40.     if (empPage == null ) empPage = RowSetPage.EMPTY_PAGE;
  41. %>
  42.     …
  43.     "0" width="90%">
  44.         ID代码用户名姓名  
  45. <%
  46.     javax.sql. empRS = (javax.sql.) empPage.getRowSet();
  47.     if (empRS!=nullwhile (empRS.next() ) {
  48. %>
  49.           
  50.             <%= empRS.getString("EMP_ID")%>
  51.             <%= empRS.getString("EMP_CODE")%>  
  52.             <%= empRS.getString("USER_NAME")%>
  53.             <%= empRS.getString("REAL_NAME")%>  
  54.         
  55. <%
  56.     }// end while
  57. %>
  58.         
  59. <%
  60.     //显示总页数和当前页数(pageno)以及分页代码。
  61.     //此处doQuery为页面上提交查询动作的javascript函数名, pageno为标识当前页码的参数名
  62. %>
  63.             <%= empPage .getHTML("doQuery""pageno")%>
  64.         
  65.     
  66.     

  效果如图:

  因为分页显示一般都会伴有查询条件和查询动作,页面应已经有校验查询条件和提交查询的javascript方法(如上面的doQuery),所以RowSetPage.getHTML()生成的分页代码在用户选择新页码时直接回调前面的处理提交查询的javascript方法。注意在显示查询结果的时候上次的查询条件也需要保持,如">。同时由于页码的参数名可以指定,因此也支持在同一页面中有多个分页区。

  另一种分页代码实现是生成每一页的URL,将查询参数和页码作为QueryString附在URL后面。这种方法的缺陷是在查询条件比较复杂时难以处理,并且需要指定处理查询动作的servlet,可能不适合某些定制的查询操作。

  如果对RowSetPage.getHTML()生成的默认分页代码不满意可以编写自己的分页处理代码,RowSetPage提供了很多getter方法用于获取相关信息(如当前页码、总页数、 总记录数和当前记录数等)。

  在实际应用中可以将分页查询和显示做成jsp taglib, 进一步简化JSP代码,屏蔽Java Code。

附:分页工具类的源代码, 有注释,应该很容易理解。

1.Page.java

2.RowSetPage.java(RowSetPage继承Page)

3.PagedStatement.java

4.PagedStatementOracleImpl.java(PagedStatementOracleImpl继承PagedStatement)

您可以任意使用这些源代码,但必须保留author evan_zhao@hotmail.com字样

  1. ///////////////////////////////////
  2. //
  3. //  Page.java
  4. //  author: evan_zhao@hotmail.com
  5. //
  6. ///////////////////////////////////
  7. package page;
  8. import java.util.;
  9. import java.util.;
  10. import java.util.;
  11. import java.util.;
  12. /**
  13.  * Title: 分页对象
  14.  * Description:  用于包含数据及分页信息的对象
  15.  *               Page类实现了用于显示分页信息的基本方法,但未指定所含数据的类型,
  16.  *               可根据需要实现以特定方式组织数据的子类,
  17.  *               如RowSetPage以RowSet封装数据,ListPage以List封装数据
  18.  * Copyright:    Copyright (c) 2002 
  19.  * @author evan_zhao@hotmail.com 
  20.  * @version 1.0
  21.  */
  22. public  class Page implements java.io. {
  23.     publicstaticfinal Page EMPTY_PAGE = new Page();
  24.     publicstaticfinalint  DEFAULT_PAGE_SIZE = 20;
  25.     publicstaticfinal  int MAX_PAGE_SIZE = 9999;
  26.     privateint myPageSize = DEFAULT_PAGE_SIZE;
  27.     privateint start;
  28.     privateint avaCount,totalSize;
  29.     private data;
  30.     privateint currentPageno;
  31.     privateint totalPageCount;
  32.     /**
  33.      * 默认构造方法,只构造空页
  34.      */
  35.     protected Page(){
  36.         this.init(0,0,0,DEFAULT_PAGE_SIZE,new());
  37.     }
  38.     /**
  39.      * 分页数据初始方法,由子类调用
  40.      * @param start 本页数据在数据库中的起始位置
  41.      * @param avaCount 本页包含的数据条数
  42.      * @param totalSize 数据库中总记录条数
  43.      * @param pageSize 本页容量
  44.      * @param data 本页包含的数据
  45.      */
  46.     protectedvoid init(int start, int avaCount, int totalSize, int pageSize,  data){
  47.         this.avaCount =avaCount;
  48.         this.myPageSize = pageSize;
  49.         this.start = start;
  50.         this.totalSize = totalSize;
  51.         this.data=data;
  52.         //System.out.println("avaCount:"+avaCount);
  53.         //System.out.println("totalSize:"+totalSize);
  54.         if (avaCount>totalSize) {
  55.             //throw new RuntimeException("记录条数大于总条数?!");
  56.         }
  57.         this.currentPageno = (start -1)/pageSize +1;
  58.         this.totalPageCount = (totalSize + pageSize -1) / pageSize;
  59.         if (totalSize==0 && avaCount==0){
  60.             this.currentPageno = 1;
  61.             this.totalPageCount = 1;
  62.         }
  63.         //System.out.println("Start Index to Page No: " + start + "-" + currentPageno);
  64.     }
  65.     public   getData(){
  66.         returnthis.data;
  67.     }
  68.     /**
  69.      * 取本页数据容量(本页能包含的记录数)
  70.      * @return 本页能包含的记录数
  71.      */
  72.     publicint getPageSize(){
  73.         returnthis.myPageSize;
  74.     }
  75.     /**
  76.      * 是否有下一页
  77.      * @return 是否有下一页
  78.      */
  79.     publicboolean hasNextPage() {
  80.       /*
  81.         if (avaCount==0 && totalSize==0){
  82.             return false;
  83.         }
  84.         return (start + avaCount -1) < totalSize;
  85.        */
  86.       return (this.getCurrentPageNo()<this.getTotalPageCount());
  87.     }
  88.     /**
  89.      * 是否有上一页
  90.      * @return  是否有上一页
  91.      */
  92.     publicboolean hasPreviousPage() {
  93.       /*
  94.         return start > 1;
  95.        */
  96.       return (this.getCurrentPageNo()>1);
  97.     }
  98.     /**
  99.      * 获取当前页第一条数据在数据库中的位置
  100.      * @return
  101.      */
  102.     publicint getStart(){
  103.         return start;
  104.     }
  105.     /**
  106.      * 获取当前页最后一条数据在数据库中的位置
  107.      * @return
  108.      */
  109.     publicint getEnd(){
  110.         int end = this.getStart() + this.getSize() -1;
  111.         if (end<0) {
  112.             end = 0;
  113.         }
  114.         return end;
  115.     }
  116.     /**
  117.      * 获取上一页第一条数据在数据库中的位置
  118.      * @return 记录对应的rownum
  119.      */
  120.     publicint getStartOfPreviousPage() {
  121.         return.max(start-myPageSize, 1);
  122.     }
  123.     /**
  124.      * 获取下一页第一条数据在数据库中的位置
  125.      * @return 记录对应的rownum
  126.      */
  127.     publicint getStartOfNextPage() {
  128.         return start + avaCount;
  129.     }
  130.     /**
  131.      * 获取任一页第一条数据在数据库中的位置,每页条数使用默认值
  132.      * @param pageNo 页号
  133.      * @return 记录对应的rownum
  134.      */
  135.     publicstaticint getStartOfAnyPage(int pageNo){
  136.         return getStartOfAnyPage(pageNo, DEFAULT_PAGE_SIZE);
  137.     }
  138.     /**
  139.      * 获取任一页第一条数据在数据库中的位置
  140.      * @param pageNo 页号
  141.      * @param pageSize 每页包含的记录数
  142.      * @return 记录对应的rownum
  143.      */
  144.     publicstaticint getStartOfAnyPage(int pageNo, int pageSize){
  145.         int startIndex = (pageNo-1) * pageSize + 1;
  146.         if ( startIndex < 1) startIndex = 1;
  147.         //System.out.println("Page No to Start Index: " + pageNo + "-" + startIndex);
  148.         return startIndex;
  149.     }
  150.     /**
  151.      * 取本页包含的记录数
  152.      * @return 本页包含的记录数
  153.      */
  154.     publicint getSize() {
  155.         return avaCount;
  156.     }
  157.     /**
  158.      * 取数据库中包含的总记录数
  159.      * @return 数据库中包含的总记录数
  160.      */
  161.     publicint getTotalSize() {
  162.         returnthis.totalSize;
  163.     }
  164.     /**
  165.      * 取当前页码
  166.      * @return 当前页码
  167.      */
  168.     publicint getCurrentPageNo(){
  169.         return  this.currentPageno;
  170.     }
  171.     /**
  172.      * 取总页码
  173.      * @return 总页码
  174.      */
  175.     publicint getTotalPageCount(){
  176.         returnthis.totalPageCount;
  177.     }
  178.     /**
  179.      *
  180.      * @param queryJSFunctionName 实现分页的JS脚本名字,页码变动时会自动回调该方法
  181.      * @param pageNoParamName 页码参数名称
  182.      * @return
  183.      */
  184.     public getHTML( queryJSFunctionName,  pageNoParamName){
  185.         if (getTotalPageCount()<1){
  186.             return"+pageNoParamName+"' value='1' >";
  187.         }
  188.         if (queryJSFunctionName == null || queryJSFunctionName.trim().length()<1) {
  189.             queryJSFunctionName = "gotoPage";
  190.         }
  191.         if (pageNoParamName == null || pageNoParamName.trim().length()<1){
  192.             pageNoParamName = "pageno";
  193.         }
  194.          gotoPage = "_"+queryJSFunctionName;
  195.          html = new("\n");
  196.         html.append("\n")
  197.              .append("function ").append(gotoPage).append("(pageNo){  \n")
  198.              .append(  "   var curPage=1;  \n")
  199.              .append(  "   try{ curPage = document.all[\"")
  200.              .append(pageNoParamName).append("\"].value;  \n")
  201.              .append(  "        document.all[\"").append(pageNoParamName)
  202.              .append("\"].value = pageNo;  \n")
  203.              .append(  "        ").append(queryJSFunctionName).append("(pageNo); \n")
  204.              .append(  "        return true;  \n")
  205.              .append(  "   }catch(e){ \n")
  206. //             .append(  "      try{ \n")
  207. //             .append(  "           document.forms[0].submit();  \n")
  208. //             .append(  "      }catch(e){   \n")
  209.              .append(  "          alert('尚未定义查询方法:function ")
  210.              .append(queryJSFunctionName).append("()'); \n")
  211.              .append(  "          document.all[\"").append(pageNoParamName)
  212.              .append("\"].value = curPage;  \n")
  213.              .append(  "          return false;  \n")
  214. //             .append(  "      }  \n")
  215.              .append(  "   }  \n")
  216.              .append(  "}")
  217.              .append(  "  \n")
  218.              .append(  "");
  219.         html.append( "  \n")
  220.              .append( "    \n")
  221.              .append( "    
      \n"
    );
  222.         html.append(  "       共" ).append( getTotalPageCount() ).append( "页")
  223.              .append(  "       [") .append(getStart()).append("..").append(getEnd())
  224.              .append("/").append(this.getTotalSize()).append("]  \n")
  225.              .append( "      \n")
  226.              .append( "      \n");
  227.         if (hasPreviousPage()){
  228.              html.append( "[).append(gotoPage)
  229.              .append("(") .append(getCurrentPageNo()-1) 
  230.              .append( ")'>上一页]   \n");
  231.         }
  232.         html.append(  "       第")
  233.              .append(   "        )
  234.              .append(pageNoParamName).append("' onChange='javascript:")
  235.              .append(gotoPage).append("(this.value)'>\n");
  236.          selected = "selected";
  237.         for(int i=1;i<=getTotalPageCount();i++){
  238.             if( i == getCurrentPageNo() )
  239.                  selected = "selected";
  240.             else selected = "";
  241.             html.append( "      ).append(i).append("' ")
  242.               .append(selected).append(">").append(i).append("  \n");
  243.         }
  244.         if (getCurrentPageNo()>getTotalPageCount()){
  245.             html.append( "      ).append(getCurrentPageNo())
  246.             .append("' selected>").append(getCurrentPageNo())
  247.             .append("  \n");
  248.         }
  249.         html.append( "    页  \n");
  250.         if (hasNextPage()){
  251.              html.append( "    [).append(gotoPage)
  252.                .append("(").append((getCurrentPageNo()+1)) 
  253.                .append( ")'>下一页]   \n");
  254.         }
  255.         html.append( "  \n");
  256.         return html.toString();
  257.     }
  258. }
  259. ///////////////////////////////////
  260. //
  261. //  RowSetPage.java
  262. //  author: evan_zhao@hotmail.com
  263. //
  264. ///////////////////////////////////
  265. package page;
  266. import javax.sql.;
  267. /**
  268.  * 

    Title: RowSetPage

  269.  * 

    Description: 使用RowSet封装数据的分页对象

  270.  * 

    Copyright: Copyright (c) 2003

  271.  * @author evan_zhao@hotmail.com
  272.  * @version 1.0
  273.  */
  274. publicclass RowSetPage extends Page {
  275.     private javax.sql. rs;
  276.     /**
  277.      *空页
  278.      */
  279.     publicstaticfinal RowSetPage EMPTY_PAGE = new RowSetPage();
  280.     /**
  281.      *默认构造方法,创建空页
  282.      */
  283.     public RowSetPage(){
  284.       this(null, 0,0);
  285.     }
  286.     /**
  287.      *构造分页对象
  288.      *@param crs 包含一页数据的OracleCachedRowSet
  289.      *@param start 该页数据在数据库中的起始位置
  290.      *@param totalSize 数据库中包含的记录总数
  291.      */
  292.     public RowSetPage( crs, int start, int totalSize) {
  293.         this(crs,start,totalSize,Page.DEFAULT_PAGE_SIZE);
  294.     }
  295.     /**
  296.      *构造分页对象
  297.      *@param crs 包含一页数据的OracleCachedRowSet
  298.      *@param start 该页数据在数据库中的起始位置
  299.      *@param totalSize 数据库中包含的记录总数
  300.      *@pageSize 本页能容纳的记录数
  301.      */
  302.     public RowSetPage( crs, int start, int totalSize, int pageSize) {
  303.         try{
  304.             int avaCount=0;
  305.             if (crs!=null) {
  306.                 crs.beforeFirst();
  307.                 if (crs.next()){
  308.                     crs.last();
  309.                     avaCount = crs.getRow();
  310.                 }
  311.                 crs.beforeFirst();
  312.             }
  313.             rs = crs;
  314.             super.init(start,avaCount,totalSize,pageSize,rs);
  315.         }catch(java.sql. sqle){
  316.             thrownew(sqle.toString());
  317.         }
  318.     }
  319.     /**
  320.      *取分页对象中的记录数据
  321.      */
  322.     public javax.sql. getRowSet(){
  323.         return rs;
  324.     }
  325. }
  326. ///////////////////////////////////
  327. //
  328. //  PagedStatement.java
  329. //  author: evan_zhao@hotmail.com
  330. //
  331. ///////////////////////////////////
  332. package page;
  333. import foo.DBUtil;
  334. import java.math.;
  335. import java.util.;
  336. import java.util.;
  337. import java.util.;
  338. import java.sql.;
  339. import java.sql.;
  340. import java.sql.;
  341. import java.sql.;
  342. import java.sql.;
  343. import java.sql.;
  344. import javax.sql.;
  345. /**
  346.  * 

    Title: 分页查询

  347.  * 

    Description: 根据查询语句和页码查询出当页数据

  348.  * 

    Copyright: Copyright (c) 2002

  349.  * @author evan_zhao@hotmail.com
  350.  * @version 1.0
  351.  */
  352. publicabstractclass PagedStatement {
  353.     publicfinalstaticint MAX_PAGE_SIZE = Page.MAX_PAGE_SIZE;
  354.     protected countSQL, querySQL;
  355.     protectedint pageNo,pageSize,startIndex,totalCount;
  356.     protected javax.sql. rowSet;
  357.     protected RowSetPage rowSetPage;
  358.     private boundParams;
  359.     /**
  360.      * 构造一查询出所有数据的PageStatement
  361.      * @param sql  query sql
  362.      */
  363.     public PagedStatement( sql){
  364.         this(sql,1,MAX_PAGE_SIZE);
  365.     }
  366.     /**
  367.      * 构造一查询出当页数据的PageStatement
  368.      * @param sql  query sql
  369.      * @param pageNo  页码
  370.      */
  371.     public PagedStatement( sql, int pageNo){
  372.         this(sql, pageNo, Page.DEFAULT_PAGE_SIZE);
  373.     }
  374.     /**
  375.      * 构造一查询出当页数据的PageStatement,并指定每页显示记录条数
  376.      * @param sql query sql
  377.      * @param pageNo 页码
  378.      * @param pageSize 每页容量
  379.      */
  380.     public PagedStatement( sql, int pageNo, int pageSize){
  381.         this.pageNo = pageNo;
  382.         this.pageSize = pageSize;
  383.         this.startIndex = Page.getStartOfAnyPage(pageNo, pageSize);
  384.         this.boundParams = .synchronizedList(new java.util.());
  385.         this.countSQL = "select count(*) from ( " + sql +") ";
  386.         this.querySQL = intiQuerySQL(sql, this.startIndex, pageSize);
  387.     }
  388.     /**
  389.      *生成查询一页数据的sql语句
  390.      *@param sql 原查询语句
  391.      *@startIndex 开始记录位置
  392.      *@size 需要获取的记录数
  393.      */
  394.     protectedabstract   intiQuerySQL( sql, int startIndex, int size);
  395.     /**
  396.      *使用给出的对象设置指定参数的值
  397.      *@param index 第一个参数为1,第二个为2,。。。
  398.      *@param obj 包含参数值的对象
  399.      */
  400.     publicvoid setObject(int index,  obj) throws{
  401.         BoundParam bp = new BoundParam(index, obj);
  402.         boundParams.remove(bp);
  403.         boundParams.add( bp);
  404.     }
  405.     /**
  406.      *使用给出的对象设置指定参数的值
  407.      *@param index 第一个参数为1,第二个为2,。。。
  408.      *@param obj 包含参数值的对象
  409.      *@param targetSqlType 参数的数据库类型
  410.      */
  411.     publicvoid setObject(int index,  obj, int targetSqlType) throws{
  412.         BoundParam bp = new BoundParam(index, obj, targetSqlType);
  413.         boundParams.remove(bp);
  414.         boundParams.add(bp );
  415.     }
  416.     /**
  417.      *使用给出的对象设置指定参数的值
  418.      *@param index 第一个参数为1,第二个为2,。。。
  419.      *@param obj 包含参数值的对象
  420.      *@param targetSqlType 参数的数据库类型(常量定义在java.sql.Types中)
  421.      *@param scale 精度,小数点后的位数
  422.      * (只对targetSqlType是Types.NUMBER或Types.DECIMAL有效,其它类型则忽略)
  423.      */
  424.     publicvoid setObject(int index,  obj, int targetSqlType, int scale) throws{
  425.         BoundParam bp = new BoundParam(index, obj, targetSqlType, scale) ;
  426.         boundParams.remove(bp);
  427.         boundParams.add(bp);
  428.     }
  429.     /**
  430.      *使用给出的字符串设置指定参数的值
  431.      *@param index 第一个参数为1,第二个为2,。。。
  432.      *@param str 包含参数值的字符串
  433.      */
  434.     publicvoid setString(int index,  str)throws{
  435.         BoundParam bp = new BoundParam(index, str)  ;
  436.         boundParams.remove(bp);
  437.         boundParams.add(bp);
  438.     }
  439.     /**
  440.      *使用给出的字符串设置指定参数的值
  441.      *@param index 第一个参数为1,第二个为2,。。。
  442.      *@param timestamp 包含参数值的时间戳
  443.      */
  444.     publicvoid setTimestamp(int index,  timestamp)throws{
  445.         BoundParam bp = new BoundParam(index, timestamp)  ;
  446.         boundParams.remove(bp);
  447.         boundParams.add( bp );
  448.     }
  449.     /**
  450.      *使用给出的整数设置指定参数的值
  451.      *@param index 第一个参数为1,第二个为2,。。。
  452.      *@param value 包含参数值的整数
  453.      */
  454.     publicvoid setInt(int index, int value)throws{
  455.         BoundParam bp =  new BoundParam(index, new(value))  ;
  456.         boundParams.remove(bp);
  457.         boundParams.add( bp );
  458.     }
  459.     /**
  460.      *使用给出的长整数设置指定参数的值
  461.      *@param index 第一个参数为1,第二个为2,。。。
  462.      *@param value 包含参数值的长整数
  463.      */
  464.     publicvoid setLong(int index, long value)throws{
  465.         BoundParam bp =  new BoundParam(index, new(value))  ;
  466.         boundParams.remove(bp);
  467.         boundParams.add( bp );
  468.     }
  469.     /**
  470.      *使用给出的双精度浮点数设置指定参数的值
  471.      *@param index 第一个参数为1,第二个为2,。。。
  472.      *@param value 包含参数值的双精度浮点数
  473.      */
  474.     publicvoid setDouble(int index, double value)throws{
  475.         BoundParam bp =  new BoundParam(index, new(value))   ;
  476.         boundParams.remove(bp);
  477.         boundParams.add( bp);
  478.     }
  479.     /**
  480.      *使用给出的BigDecimal设置指定参数的值
  481.      *@param index 第一个参数为1,第二个为2,。。。
  482.      *@param bd 包含参数值的BigDecimal
  483.      */
  484.     publicvoid setBigDecimal(int index,  bd)throws{
  485.         BoundParam bp =   new BoundParam(index, bd )   ;
  486.         boundParams.remove(bp);
  487.         boundParams.add( bp);
  488.     }
  489.     private  void setParams( pst) throws{
  490.         if (pst==null || this.boundParams==null || this.boundParams.size()==0 ) return ;
  491.         BoundParam param;
  492.         for ( itr = this.boundParams.iterator();itr.hasNext();){
  493.             param = (BoundParam) itr.next();
  494.             if  (param==nullcontinue;
  495.             if (param.sqlType == java.sql..OTHER){
  496.                 pst.setObject(param.index, param.value);
  497.             }else{
  498.                 pst.setObject(param.index, param.value, param.sqlType, param.scale);
  499.             }
  500.         }
  501.     }
  502.     /**
  503.      * 执行查询取得一页数据,执行结束后关闭数据库连接
  504.      * @return RowSetPage
  505.      * @throws SQLException
  506.      */
  507.     public  RowSetPage executeQuery() throws{
  508.         .out.println("executeQueryUsingPreparedStatement");
  509.          conn = DBUtil.getConnection();
  510.          pst = null;
  511.          rs = null;
  512.         try{
  513.             pst = conn.prepareStatement(this.countSQL);
  514.             setParams(pst);
  515.             rs =pst.executeQuery();
  516.             if (rs.next()){
  517.                 totalCount = rs.getInt(1);
  518.             } else {
  519.                 totalCount = 0;
  520.             }
  521.             rs.close();
  522.             pst.close();
  523.             if (totalCount < 1 ) return RowSetPage.EMPTY_PAGE;
  524.             pst = conn.prepareStatement(this.querySQL);
  525.             .out.println(querySQL);
  526.             pst.setFetchSize(this.pageSize);
  527.             setParams(pst);
  528.             rs =pst.executeQuery();
  529.             //rs.setFetchSize(pageSize);
  530.             this.rowSet = populate(rs);
  531.             rs.close();
  532.             rs = null;
  533.             pst.close();
  534.             pst = null;
  535.             this.rowSetPage = new RowSetPage(this.rowSet,startIndex,totalCount,pageSize);
  536.             returnthis.rowSetPage;
  537.         }catch( sqle){
  538.             //System.out.println("executeQuery SQLException");
  539.             sqle.printStackTrace();
  540.             throw sqle;
  541.         }catch( e){
  542.             e.printStackTrace();
  543.             thrownew(e.toString());
  544.         }finally{
  545.             //System.out.println("executeQuery finally");
  546.             DBUtil.close(rs, pst, conn);
  547.         }
  548.     }
  549.     /**
  550.      *将ResultSet数据填充进CachedRowSet
  551.      */
  552.     protectedabstract populate( rs) throws;
  553.     /**
  554.      *取封装成RowSet查询结果
  555.      *@return RowSet
  556.      */
  557.     public javax.sql. getRowSet(){
  558.         returnthis.rowSet;
  559.     }
  560.     /**
  561.      *取封装成RowSetPage的查询结果
  562.      *@return RowSetPage
  563.      */
  564.     public RowSetPage getRowSetPage() {
  565.         returnthis.rowSetPage;
  566.     }
  567.     /**
  568.      *关闭数据库连接
  569.      */
  570.     publicvoid close(){
  571.         //因为数据库连接在查询结束或发生异常时即关闭,此处不做任何事情
  572.         //留待扩充。
  573.     }
  574.     privateclass BoundParam {
  575.         int index;
  576.          value;
  577.         int sqlType;
  578.         int scale;
  579.         public BoundParam(int index,  value) {
  580.             this(index, value, java.sql..OTHER);
  581.         }
  582.         public BoundParam(int index,  value, int sqlType) {
  583.             this(index, value, sqlType, 0);
  584.         }
  585.         public BoundParam(int index,  value, int sqlType, int scale) {
  586.             this.index = index;
  587.             this.value = value;
  588.             this.sqlType = sqlType;
  589.             this.scale = scale;
  590.         }
  591.         publicboolean equals( obj){
  592.             if (obj!=null&&this.getClass().isInstance(obj)){
  593.                 BoundParam bp = (BoundParam)obj;
  594.                 if (this.index==bp.index) returntrue;
  595.             }
  596.             returnfalse;
  597.         }
  598.     }
  599. }
  600. ///////////////////////////////////
  601. //
  602. //  PagedStatementOracleImpl.java
  603. //  author: evan_zhao@hotmail.com
  604. //
  605. ///////////////////////////////////
  606. package page;
  607. import java.sql.;
  608. import java.sql.;
  609. import javax.sql.;
  610. import oracle.jdbc.rowset.OracleCachedRowSet;
  611. /**
  612.  * 

    Title: 分页查询Oracle数据库实现

  613.  * 

    Copyright: Copyright (c) 2002

  614.  * @author evan_zhao@hotmail.com
  615.  * @version 1.0
  616.  */
  617. publicclass PagedStatementOracleImpl extends PagedStatement {
  618.     /**
  619.      * 构造一查询出所有数据的PageStatement
  620.      * @param sql  query sql
  621.      */
  622.     public PagedStatementOracleImpl( sql){
  623.         super(sql);
  624.     }
  625.     /**
  626.      * 构造一查询出当页数据的PageStatement
  627.      * @param sql  query sql
  628.      * @param pageNo  页码
  629.      */
  630.     public PagedStatementOracleImpl( sql, int pageNo){
  631.         super(sql, pageNo);
  632.     }
  633.     /**
  634.      * 构造一查询出当页数据的PageStatement,并指定每页显示记录条数
  635.      * @param sql query sql
  636.      * @param pageNo 页码
  637.      * @param pageSize 每页容量
  638.      */
  639.     public PagedStatementOracleImpl( sql, int pageNo, int pageSize){
  640.         super(sql, pageNo, pageSize);
  641.     }
  642.     /**
  643.      *生成查询一页数据的sql语句
  644.      *@param sql 原查询语句
  645.      *@startIndex 开始记录位置
  646.      *@size 需要获取的记录数
  647.      */
  648.     protected intiQuerySQL( sql, int startIndex, int size){
  649.          querySQL = new();
  650.         if (size != super.MAX_PAGE_SIZE) {
  651.             querySQL.append("select * from (select my_table.*,rownum as my_rownum from(")
  652.                     .append(  sql)
  653.                     .append(") my_table where rownum<").append(startIndex + size)
  654.                     .append(") where my_rownum>=").append(startIndex);
  655.         } else {
  656.             querySQL.append("select * from (select my_table.*,rownum as my_rownum from(")
  657.                     .append(sql)
  658.                     .append(") my_table ")
  659.                     .append(") where my_rownum>=").append(startIndex);
  660.         }
  661.         return querySQL.toString();
  662.     }
  663.     /**
  664.      *将ResultSet数据填充进CachedRowSet
  665.      */
  666.     protected   populate( rs) throws{
  667.         OracleCachedRowSet ocrs = new OracleCachedRowSet();
  668.         ocrs.populate(rs);
  669.         return ocrs;
  670.     }
  671. }

出处: 作者:佚名

 

 

源文档 <>

 

阅读(1286) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~