目前比較廣泛使用的分頁方式是將查詢結(jié)果緩存在HttpSession或有狀態(tài)bean中,翻頁的時候從緩存中取出一頁數(shù)據(jù)顯示。這種方法有兩個主要的缺點:一是用戶可能看到的是過期數(shù)據(jù);二是如果數(shù)據(jù)量非常大時第一次查詢遍歷結(jié)果集會耗費很長時間,并且緩存的數(shù)據(jù)也會占用大量內(nèi)存,效率明顯下降。 其它常見的方法還有每次翻頁都查詢一次數(shù)據(jù)庫,從ResultSet中只取出一頁數(shù)據(jù)(使用rs.last();rs.getRow()獲得總計錄條數(shù),使用rs.absolute()定位到本頁起始記錄)。這種方式在某些數(shù)據(jù)庫(如oracle)的JDBC實現(xiàn)中差不多也是需要遍歷所有記錄,實驗證明在記錄數(shù)很大時速度非常慢。 至于緩存結(jié)果集ResultSet的方法則完全是一種錯誤的做法。因為ResultSet在Statement或Connection關(guān)閉時也會被關(guān)閉,如果要使ResultSet有效勢必長時間占用數(shù)據(jù)庫連接。
因此比較好的分頁做法應(yīng)該是每次翻頁的時候只從數(shù)據(jù)庫里檢索頁面大小的塊區(qū)的數(shù)據(jù)。這樣雖然每次翻頁都需要查詢數(shù)據(jù)庫,但查詢出的記錄數(shù)很少,網(wǎng)絡(luò)傳輸數(shù)據(jù)量不大,如果使用連接池更可以略過最耗時的建立數(shù)據(jù)庫連接過程。而在數(shù)據(jù)庫端有各種成熟的優(yōu)化技術(shù)用于提高查詢速度,比在應(yīng)用服務(wù)器層做緩存有效多了。
在oracle數(shù)據(jù)庫中查詢結(jié)果的行號使用偽列ROWNUM表示(從1開始)。例如select * from employee where rownum<10 返回前10條記錄。但因為rownum是在查詢之后排序之前賦值的,所以查詢employee按birthday排序的第100到120條記錄應(yīng)該這么寫: [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()函數(shù)用于獲取當(dāng)前行數(shù)。 SQL Server沒研究過,可以參考這篇文章:http://www.csdn.net/develop/article/18/18627.shtm
在Web程序中分頁會被頻繁使用,但分頁的實現(xiàn)細節(jié)卻是編程過程中比較麻煩的事情。大多分頁顯示的查詢操作都同時需要處理復(fù)雜的多重查詢條件,sql語句需要動態(tài)拼接組成,再加上分頁需要的記錄定位、總記錄條數(shù)查詢以及查詢結(jié)果的遍歷、封裝和顯示,程序會變得很復(fù)雜并且難以理解。因此需要一些工具類簡化分頁代碼,使程序員專注于業(yè)務(wù)邏輯部分。下面是我設(shè)計的兩個工具類: PagedStatement 封裝了數(shù)據(jù)庫連接、總記錄數(shù)查詢、分頁查詢、結(jié)果數(shù)據(jù)封裝和關(guān)閉數(shù)據(jù)庫連接等操作,并使用了PreparedStatement支持動態(tài)設(shè)置參數(shù)。 RowSetPage 參考PetStore的page by page iterator模式, 設(shè)計RowSetPage用于封裝查詢結(jié)果(使用OracleCachedRowSet緩存查詢出的一頁數(shù)據(jù),關(guān)于使用CachedRowSet封裝數(shù)據(jù)庫查詢結(jié)果請參考JSP頁面查詢顯示常用模式)以及當(dāng)前頁碼、總記錄條數(shù)、當(dāng)前記錄數(shù)等信息, 并且可以生成簡單的HTML分頁代碼。 PagedStatement 查詢的結(jié)果封裝成RowsetPage。
下面是簡單的使用示例:
//DAO查詢數(shù)據(jù)部分代碼: … public RowSetPage getEmployee(String gender, int pageNo) throws Exception{ String sql="select emp_id, emp_code, user_name, real_name from employee where gender =?"; //使用Oracle數(shù)據(jù)庫的分頁查詢實現(xiàn),每頁顯示5條 PagedStatement pst =new PagedStatementOracleImpl(sql, pageNo, 5); pst.setString(1, gender); return pst.executeQuery(); }
//Servlet處理查詢請求部分代碼:
… int pageNo; try{ //可以通過參數(shù)pageno獲得用戶選擇的頁碼 pageNo = Integer.parseInt(request.getParameter("pageno") ); }catch(Exception ex){ //默認為第一頁 pageNo=1; } String gender = request.getParameter("gender" ); request.setAttribute("empPage", myBean.getEmployee(gender, pageNo) ); …
//JSP顯示部分代碼 <%@ page import = "page.RowSetPage"%> … <script language="javascript"> function doQuery(){ form1.actionType.value="doQuery"; form1.submit(); } </script> … <form name=form1 method=get> <input type=hidden name=actionType> 性別: <input type=text name=gender size=1 value="<%=request.getParameter("gender")%>"> <input type=button value=" 查詢 " onclick="doQuery()"> <% RowSetPage empPage = (RowSetPage)request.getAttribute("empPage"); if (empPage == null ) empPage = RowSetPage.EMPTY_PAGE; %> … <table cellspacing="0" width="90%"> <tr> <td>ID</td> <td>代碼</td> <td>用戶名</td> <td>姓名</td> </tr> <% javax.sql.RowSet empRS = (javax.sql.RowSet) empPage.getRowSet(); if (empRS!=null) while (empRS.next() ) { %> <tr> <td><%= empRS.getString("EMP_ID")%></td> <td><%= empRS.getString("EMP_CODE")%></td> <td><%= empRS.getString("USER_NAME")%></td> <td><%= empRS.getString("REAL_NAME")%></td> </tr> <% }// end while %> <tr> <% //顯示總頁數(shù)和當(dāng)前頁數(shù)(pageno)以及分頁代碼。 //此處doQuery為頁面上提交查詢動作的javascript函數(shù)名, pageno為標(biāo)識當(dāng)前頁碼的參數(shù)名 %> <td colspan=4><%= empPage .getHTML("doQuery", "pageno")%></td> </tr> </table> </form>
效果如圖:
因為分頁顯示一般都會伴有查詢條件和查詢動作,頁面應(yīng)已經(jīng)有校驗查詢條件和提交查詢的javascript方法(如上面的doQuery),所以RowSetPage.getHTML()生成的分頁代碼在用戶選擇新頁碼時直接回調(diào)前面的處理提交查詢的javascript方法。注意在顯示查詢結(jié)果的時候上次的查詢條件也需要保持,如<input type=text name=gender size=1 value="<%=request.getParameter("gender")%>">。同時由于頁碼的參數(shù)名可以指定,因此也支持在同一頁面中有多個分頁區(qū)。 另一種分頁代碼實現(xiàn)是生成每一頁的URL,將查詢參數(shù)和頁碼作為QueryString附在URL后面。這種方法的缺陷是在查詢條件比較復(fù)雜時難以處理,并且需要指定處理查詢動作的servlet,可能不適合某些定制的查詢操作。 如果對RowSetPage.getHTML()生成的默認分頁代碼不滿意可以編寫自己的分頁處理代碼,RowSetPage提供了很多getter方法用于獲取相關(guān)信息(如當(dāng)前頁碼、總頁數(shù)、 總記錄數(shù)和當(dāng)前記錄數(shù)等)。 在實際應(yīng)用中可以將分頁查詢和顯示做成jsp taglib, 進一步簡化JSP代碼,屏蔽Java Code。
附:分頁工具類的源代碼, 有注釋,應(yīng)該很容易理解。
1.Page.java 2.RowSetPage.java(RowSetPage繼承Page) 3.PagedStatement.java 4.PagedStatementOracleImpl.java(PagedStatementOracleImpl繼承PagedStatement)
您可以任意使用這些源代碼,但必須保留author evan_zhao@hotmail.com字樣
/////////////////////////////////// // // Page.java // author: evan_zhao@hotmail.com // ///////////////////////////////////
package page;
import java.util.List; import java.util.ArrayList; import java.util.Collection; import java.util.Collections;
/** * Title: 分頁對象<br> * Description: 用于包含數(shù)據(jù)及分頁信息的對象<br> * Page類實現(xiàn)了用于顯示分頁信息的基本方法,但未指定所含數(shù)據(jù)的類型, * 可根據(jù)需要實現(xiàn)以特定方式組織數(shù)據(jù)的子類,<br> * 如RowSetPage以RowSet封裝數(shù)據(jù),ListPage以List封裝數(shù)據(jù)<br> * Copyright: Copyright (c) 2002 <br> * @author evan_zhao@hotmail.com <br> * @version 1.0 */ public class Page implements java.io.Serializable { public static final Page EMPTY_PAGE = new Page(); public static final int DEFAULT_PAGE_SIZE = 20; public static final int MAX_PAGE_SIZE = 9999;
private int myPageSize = DEFAULT_PAGE_SIZE;
private int start; private int avaCount,totalSize; private Object data;
private int currentPageno; private int totalPageCount;
/** * 默認構(gòu)造方法,只構(gòu)造空頁 */ protected Page(){ this.init(0,0,0,DEFAULT_PAGE_SIZE,new Object()); }
/** * 分頁數(shù)據(jù)初始方法,由子類調(diào)用 * @param start 本頁數(shù)據(jù)在數(shù)據(jù)庫中的起始位置 * @param avaCount 本頁包含的數(shù)據(jù)條數(shù) * @param totalSize 數(shù)據(jù)庫中總記錄條數(shù) * @param pageSize 本頁容量 * @param data 本頁包含的數(shù)據(jù) */ protected void init(int start, int avaCount, int totalSize, int pageSize, Object data){
this.avaCount =avaCount; this.myPageSize = pageSize;
this.start = start; this.totalSize = totalSize;
this.data=data;
//System.out.println("avaCount:"+avaCount); //System.out.println("totalSize:"+totalSize); if (avaCount>totalSize) { //throw new RuntimeException("記錄條數(shù)大于總條數(shù)?!"); }
this.currentPageno = (start -1)/pageSize +1; this.totalPageCount = (totalSize + pageSize -1) / pageSize;
if (totalSize==0 && avaCount==0){ this.currentPageno = 1; this.totalPageCount = 1; } //System.out.println("Start Index to Page No: " + start + "-" + currentPageno); }
public Object getData(){ return this.data; }
/** * 取本頁數(shù)據(jù)容量(本頁能包含的記錄數(shù)) * @return 本頁能包含的記錄數(shù) */ public int getPageSize(){ return this.myPageSize; }
/** * 是否有下一頁 * @return 是否有下一頁 */ public boolean hasNextPage() { /* if (avaCount==0 && totalSize==0){ return false; } return (start + avaCount -1) < totalSize; */ return (this.getCurrentPageNo()<this.getTotalPageCount()); }
/** * 是否有上一頁 * @return 是否有上一頁 */ public boolean hasPreviousPage() { /* return start > 1; */ return (this.getCurrentPageNo()>1); }
/** * 獲取當(dāng)前頁第一條數(shù)據(jù)在數(shù)據(jù)庫中的位置 * @return */ public int getStart(){ return start; }
/** * 獲取當(dāng)前頁最后一條數(shù)據(jù)在數(shù)據(jù)庫中的位置 * @return */ public int getEnd(){ int end = this.getStart() + this.getSize() -1; if (end<0) { end = 0; } return end; }
/** * 獲取上一頁第一條數(shù)據(jù)在數(shù)據(jù)庫中的位置 * @return 記錄對應(yīng)的rownum */ public int getStartOfPreviousPage() { return Math.max(start-myPageSize, 1); }
/** * 獲取下一頁第一條數(shù)據(jù)在數(shù)據(jù)庫中的位置 * @return 記錄對應(yīng)的rownum */ public int getStartOfNextPage() { return start + avaCount; }
/** * 獲取任一頁第一條數(shù)據(jù)在數(shù)據(jù)庫中的位置,每頁條數(shù)使用默認值 * @param pageNo 頁號 * @return 記錄對應(yīng)的rownum */ public static int getStartOfAnyPage(int pageNo){ return getStartOfAnyPage(pageNo, DEFAULT_PAGE_SIZE); }
/** * 獲取任一頁第一條數(shù)據(jù)在數(shù)據(jù)庫中的位置 * @param pageNo 頁號 * @param pageSize 每頁包含的記錄數(shù) * @return 記錄對應(yīng)的rownum */ public static int getStartOfAnyPage(int pageNo, int pageSize){ int startIndex = (pageNo-1) * pageSize + 1; if ( startIndex < 1) startIndex = 1; //System.out.println("Page No to Start Index: " + pageNo + "-" + startIndex); return startIndex; }
/** * 取本頁包含的記錄數(shù) * @return 本頁包含的記錄數(shù) */ public int getSize() { return avaCount; }
/** * 取數(shù)據(jù)庫中包含的總記錄數(shù) * @return 數(shù)據(jù)庫中包含的總記錄數(shù) */ public int getTotalSize() { return this.totalSize; }
/** * 取當(dāng)前頁碼 * @return 當(dāng)前頁碼 */ public int getCurrentPageNo(){ return this.currentPageno; }
/** * 取總頁碼 * @return 總頁碼 */ public int getTotalPageCount(){ return this.totalPageCount; }
/** * * @param queryJSFunctionName 實現(xiàn)分頁的JS腳本名字,頁碼變動時會自動回調(diào)該方法 * @param pageNoParamName 頁碼參數(shù)名稱 * @return */ public String getHTML(String queryJSFunctionName, String pageNoParamName){ if (getTotalPageCount()<1){ return "<input type=‘hidden‘ name=‘"+pageNoParamName+"‘ value=‘1‘ >"; } if (queryJSFunctionName == null || queryJSFunctionName.trim().length()<1) { queryJSFunctionName = "gotoPage"; } if (pageNoParamName == null || pageNoParamName.trim().length()<1){ pageNoParamName = "pageno"; }
String gotoPage = "_"+queryJSFunctionName;
StringBuffer html = new StringBuffer("\n"); html.append("<script language=\"Javascript1.2\">\n") .append("function ").append(gotoPage).append("(pageNo){ \n") .append( " var curPage=1; \n") .append( " try{ curPage = document.all[\"") .append(pageNoParamName).append("\"].value; \n") .append( " document.all[\"").append(pageNoParamName) .append("\"].value = pageNo; \n") .append( " ").append(queryJSFunctionName).append("(pageNo); \n") .append( " return true; \n") .append( " }catch(e){ \n") // .append( " try{ \n") // .append( " document.forms[0].submit(); \n") // .append( " }catch(e){ \n") .append( " alert(‘尚未定義查詢方法:function ") .append(queryJSFunctionName).append("()‘); \n") .append( " document.all[\"").append(pageNoParamName) .append("\"].value = curPage; \n") .append( " return false; \n") // .append( " } \n") .append( " } \n") .append( "}") .append( "</script> \n") .append( ""); html.append( "<table border=0 cellspacing=0 cellpadding=0 align=center width=80%> \n") .append( " <tr> \n") .append( " <td align=left><br> \n"); html.append( " 共" ).append( getTotalPageCount() ).append( "頁") .append( " [") .append(getStart()).append("..").append(getEnd()) .append("/").append(this.getTotalSize()).append("] \n") .append( " </td> \n") .append( " <td align=right> \n"); if (hasPreviousPage()){ html.append( "[<a href=‘javascript:").append(gotoPage) .append("(") .append(getCurrentPageNo()-1) .append( ")‘>上一頁</a>] \n"); } html.append( " 第") .append( " <select name=‘") .append(pageNoParamName).append("‘ onChange=‘javascript:") .append(gotoPage).append("(this.value)‘>\n"); String selected = "selected"; for(int i=1;i<=getTotalPageCount();i++){ if( i == getCurrentPageNo() ) selected = "selected"; else selected = ""; html.append( " <option value=‘").append(i).append("‘ ") .append(selected).append(">").append(i).append("</option> \n"); } if (getCurrentPageNo()>getTotalPageCount()){ html.append( " <option value=‘").append(getCurrentPageNo()) .append("‘ selected>").append(getCurrentPageNo()) .append("</option> \n"); } html.append( " </select>頁 \n"); if (hasNextPage()){ html.append( " [<a href=‘javascript:").append(gotoPage) .append("(").append((getCurrentPageNo()+1)) .append( ")‘>下一頁</a>] \n"); } html.append( "</td></tr></table> \n");
return html.toString();
} }
/////////////////////////////////// // // RowSetPage.java // author: evan_zhao@hotmail.com // /////////////////////////////////// package page;
import javax.sql.RowSet;
/** * <p>Title: RowSetPage</p> * <p>Description: 使用RowSet封裝數(shù)據(jù)的分頁對象</p> * <p>Copyright: Copyright (c) 2003</p> * @author evan_zhao@hotmail.com * @version 1.0 */
public class RowSetPage extends Page { private javax.sql.RowSet rs;
/** *空頁 */ public static final RowSetPage EMPTY_PAGE = new RowSetPage();
/** *默認構(gòu)造方法,創(chuàng)建空頁 */ public RowSetPage(){ this(null, 0,0); }
/** *構(gòu)造分頁對象 *@param crs 包含一頁數(shù)據(jù)的OracleCachedRowSet *@param start 該頁數(shù)據(jù)在數(shù)據(jù)庫中的起始位置 *@param totalSize 數(shù)據(jù)庫中包含的記錄總數(shù) */ public RowSetPage(RowSet crs, int start, int totalSize) { this(crs,start,totalSize,Page.DEFAULT_PAGE_SIZE); }
/** *構(gòu)造分頁對象 *@param crs 包含一頁數(shù)據(jù)的OracleCachedRowSet *@param start 該頁數(shù)據(jù)在數(shù)據(jù)庫中的起始位置 *@param totalSize 數(shù)據(jù)庫中包含的記錄總數(shù) *@pageSize 本頁能容納的記錄數(shù) */ public RowSetPage(RowSet crs, int start, int totalSize, int pageSize) { try{ int avaCount=0; if (crs!=null) { crs.beforeFirst(); if (crs.next()){ crs.last(); avaCount = crs.getRow(); } crs.beforeFirst(); } rs = crs; super.init(start,avaCount,totalSize,pageSize,rs); }catch(java.sql.SQLException sqle){ throw new RuntimeException(sqle.toString()); } }
/** *取分頁對象中的記錄數(shù)據(jù) */ public javax.sql.RowSet getRowSet(){ return rs; }
}
/////////////////////////////////// // // PagedStatement.java // author: evan_zhao@hotmail.com // ///////////////////////////////////
package page;
import foo.DBUtil;
import java.math.BigDecimal; import java.util.List; import java.util.Iterator; import java.util.Collections;
import java.sql.Connection; import java.sql.SQLException; import java.sql.ResultSet; import java.sql.Statement; import java.sql.PreparedStatement; import java.sql.Timestamp; import javax.sql.RowSet;
/** * <p>Title: 分頁查詢</p> * <p>Description: 根據(jù)查詢語句和頁碼查詢出當(dāng)頁數(shù)據(jù)</p> * <p>Copyright: Copyright (c) 2002</p> * @author evan_zhao@hotmail.com * @version 1.0 */ public abstract class PagedStatement { public final static int MAX_PAGE_SIZE = Page.MAX_PAGE_SIZE;
protected String countSQL, querySQL; protected int pageNo,pageSize,startIndex,totalCount; protected javax.sql.RowSet rowSet; protected RowSetPage rowSetPage;
private List boundParams;
/** * 構(gòu)造一查詢出所有數(shù)據(jù)的PageStatement * @param sql query sql */ public PagedStatement(String sql){ this(sql,1,MAX_PAGE_SIZE); }
/** * 構(gòu)造一查詢出當(dāng)頁數(shù)據(jù)的PageStatement * @param sql query sql * @param pageNo 頁碼 */ public PagedStatement(String sql, int pageNo){ this(sql, pageNo, Page.DEFAULT_PAGE_SIZE); }
/** * 構(gòu)造一查詢出當(dāng)頁數(shù)據(jù)的PageStatement,并指定每頁顯示記錄條數(shù) * @param sql query sql * @param pageNo 頁碼 * @param pageSize 每頁容量 */ public PagedStatement(String sql, int pageNo, int pageSize){ this.pageNo = pageNo; this.pageSize = pageSize; this.startIndex = Page.getStartOfAnyPage(pageNo, pageSize); this.boundParams = Collections.synchronizedList(new java.util.LinkedList());
this.countSQL = "select count(*) from ( " + sql +") "; this.querySQL = intiQuerySQL(sql, this.startIndex, pageSize); }
/** *生成查詢一頁數(shù)據(jù)的sql語句 *@param sql 原查詢語句 *@startIndex 開始記錄位置 *@size 需要獲取的記錄數(shù) */ protected abstract String intiQuerySQL(String sql, int startIndex, int size);
/** *使用給出的對象設(shè)置指定參數(shù)的值 *@param index 第一個參數(shù)為1,第二個為2,。。。 *@param obj 包含參數(shù)值的對象 */ public void setObject(int index, Object obj) throws SQLException{ BoundParam bp = new BoundParam(index, obj); boundParams.remove(bp); boundParams.add( bp); }
/** *使用給出的對象設(shè)置指定參數(shù)的值 *@param index 第一個參數(shù)為1,第二個為2,。。。 *@param obj 包含參數(shù)值的對象 *@param targetSqlType 參數(shù)的數(shù)據(jù)庫類型 */ public void setObject(int index, Object obj, int targetSqlType) throws SQLException{ BoundParam bp = new BoundParam(index, obj, targetSqlType); boundParams.remove(bp); boundParams.add(bp ); }
/** *使用給出的對象設(shè)置指定參數(shù)的值 *@param index 第一個參數(shù)為1,第二個為2,。。。 *@param obj 包含參數(shù)值的對象 *@param targetSqlType 參數(shù)的數(shù)據(jù)庫類型(常量定義在java.sql.Types中) *@param scale 精度,小數(shù)點后的位數(shù) * (只對targetSqlType是Types.NUMBER或Types.DECIMAL有效,其它類型則忽略) */ public void setObject(int index, Object obj, int targetSqlType, int scale) throws SQLException{ BoundParam bp = new BoundParam(index, obj, targetSqlType, scale) ; boundParams.remove(bp); boundParams.add(bp); }
/** *使用給出的字符串設(shè)置指定參數(shù)的值 *@param index 第一個參數(shù)為1,第二個為2,。。。 *@param str 包含參數(shù)值的字符串 */ public void setString(int index, String str)throws SQLException{ BoundParam bp = new BoundParam(index, str) ; boundParams.remove(bp); boundParams.add(bp); }
/** *使用給出的字符串設(shè)置指定參數(shù)的值 *@param index 第一個參數(shù)為1,第二個為2,。。。 *@param timestamp 包含參數(shù)值的時間戳 */ public void setTimestamp(int index, Timestamp timestamp)throws SQLException{ BoundParam bp = new BoundParam(index, timestamp) ; boundParams.remove(bp); boundParams.add( bp ); }
/** *使用給出的整數(shù)設(shè)置指定參數(shù)的值 *@param index 第一個參數(shù)為1,第二個為2,。。。 *@param value 包含參數(shù)值的整數(shù) */ public void setInt(int index, int value)throws SQLException{ BoundParam bp = new BoundParam(index, new Integer(value)) ; boundParams.remove(bp); boundParams.add( bp ); }
/** *使用給出的長整數(shù)設(shè)置指定參數(shù)的值 *@param index 第一個參數(shù)為1,第二個為2,。。。 *@param value 包含參數(shù)值的長整數(shù) */ public void setLong(int index, long value)throws SQLException{ BoundParam bp = new BoundParam(index, new Long(value)) ; boundParams.remove(bp); boundParams.add( bp ); }
/** *使用給出的雙精度浮點數(shù)設(shè)置指定參數(shù)的值 *@param index 第一個參數(shù)為1,第二個為2,。。。 *@param value 包含參數(shù)值的雙精度浮點數(shù) */ public void setDouble(int index, double value)throws SQLException{ BoundParam bp = new BoundParam(index, new Double(value)) ; boundParams.remove(bp); boundParams.add( bp); }
/** *使用給出的BigDecimal設(shè)置指定參數(shù)的值 *@param index 第一個參數(shù)為1,第二個為2,。。。 *@param bd 包含參數(shù)值的BigDecimal */ public void setBigDecimal(int index, BigDecimal bd)throws SQLException{ BoundParam bp = new BoundParam(index, bd ) ; boundParams.remove(bp); boundParams.add( bp); }
private void setParams(PreparedStatement pst) throws SQLException{ if (pst==null || this.boundParams==null || this.boundParams.size()==0 ) return ; BoundParam param; for (Iterator itr = this.boundParams.iterator();itr.hasNext();){ param = (BoundParam) itr.next(); if (param==null) continue; if (param.sqlType == java.sql.Types.OTHER){ pst.setObject(param.index, param.value); }else{ pst.setObject(param.index, param.value, param.sqlType, param.scale); } } }
/** * 執(zhí)行查詢?nèi)〉靡豁摂?shù)據(jù),執(zhí)行結(jié)束后關(guān)閉數(shù)據(jù)庫連接 * @return RowSetPage * @throws SQLException */ public RowSetPage executeQuery() throws SQLException{ System.out.println("executeQueryUsingPreparedStatement"); Connection conn = DBUtil.getConnection(); PreparedStatement pst = null; ResultSet rs = null; try{ pst = conn.prepareStatement(this.countSQL); setParams(pst); rs =pst.executeQuery(); if (rs.next()){ totalCount = rs.getInt(1); } else { totalCount = 0; }
rs.close(); pst.close();
if (totalCount < 1 ) return RowSetPage.EMPTY_PAGE;
pst = conn.prepareStatement(this.querySQL); System.out.println(querySQL); pst.setFetchSize(this.pageSize); setParams(pst); rs =pst.executeQuery(); //rs.setFetchSize(pageSize);
this.rowSet = populate(rs);
rs.close(); rs = null; pst.close(); pst = null;
this.rowSetPage = new RowSetPage(this.rowSet,startIndex,totalCount,pageSize); return this.rowSetPage; }catch(SQLException sqle){ //System.out.println("executeQuery SQLException"); sqle.printStackTrace(); throw sqle; }catch(Exception e){ e.printStackTrace(); throw new RuntimeException(e.toString()); }finally{ //System.out.println("executeQuery finally"); DBUtil.close(rs, pst, conn); } }
/** *將ResultSet數(shù)據(jù)填充進CachedRowSet */ protected abstract RowSet populate(ResultSet rs) throws SQLException;
/** *取封裝成RowSet查詢結(jié)果 *@return RowSet */ public javax.sql.RowSet getRowSet(){ return this.rowSet; }
/** *取封裝成RowSetPage的查詢結(jié)果 *@return RowSetPage */ public RowSetPage getRowSetPage() { return this.rowSetPage; }
/** *關(guān)閉數(shù)據(jù)庫連接 */ public void close(){ //因為數(shù)據(jù)庫連接在查詢結(jié)束或發(fā)生異常時即關(guān)閉,此處不做任何事情 //留待擴充。 }
private class BoundParam { int index; Object value; int sqlType; int scale;
public BoundParam(int index, Object value) { this(index, value, java.sql.Types.OTHER); }
public BoundParam(int index, Object value, int sqlType) { this(index, value, sqlType, 0); }
public BoundParam(int index, Object value, int sqlType, int scale) { this.index = index; this.value = value; this.sqlType = sqlType; this.scale = scale; }
public boolean equals(Object obj){ if (obj!=null && this.getClass().isInstance(obj)){ BoundParam bp = (BoundParam)obj; if (this.index==bp.index) return true; } return false; } }
}
/////////////////////////////////// // // PagedStatementOracleImpl.java // author: evan_zhao@hotmail.com // /////////////////////////////////// package page; import java.sql.ResultSet; import java.sql.SQLException; import javax.sql.RowSet; import oracle.jdbc.rowset.OracleCachedRowSet;
/** * <p>Title: 分頁查詢Oracle數(shù)據(jù)庫實現(xiàn)</p> * <p>Copyright: Copyright (c) 2002</p> * @author evan_zhao@hotmail.com * @version 1.0 */ public class PagedStatementOracleImpl extends PagedStatement {
/** * 構(gòu)造一查詢出所有數(shù)據(jù)的PageStatement * @param sql query sql */ public PagedStatementOracleImpl(String sql){ super(sql); }
/** * 構(gòu)造一查詢出當(dāng)頁數(shù)據(jù)的PageStatement * @param sql query sql * @param pageNo 頁碼 */ public PagedStatementOracleImpl(String sql, int pageNo){ super(sql, pageNo); }
/** * 構(gòu)造一查詢出當(dāng)頁數(shù)據(jù)的PageStatement,并指定每頁顯示記錄條數(shù) * @param sql query sql * @param pageNo 頁碼 * @param pageSize 每頁容量 */ public PagedStatementOracleImpl(String sql, int pageNo, int pageSize){ super(sql, pageNo, pageSize); }
/** *生成查詢一頁數(shù)據(jù)的sql語句 *@param sql 原查詢語句 *@startIndex 開始記錄位置 *@size 需要獲取的記錄數(shù) */ protected String intiQuerySQL(String sql, int startIndex, int size){ StringBuffer querySQL = new StringBuffer(); if (size != super.MAX_PAGE_SIZE) { querySQL.append("select * from (select my_table.*,rownum as my_rownum from(") .append( sql) .append(") my_table where rownum<").append(startIndex + size) .append(") where my_rownum>=").append(startIndex); } else { querySQL.append("select * from (select my_table.*,rownum as my_rownum from(") .append(sql) .append(") my_table ") .append(") where my_rownum>=").append(startIndex); } return querySQL.toString(); }
/** *將ResultSet數(shù)據(jù)填充進CachedRowSet */ protected RowSet populate(ResultSet rs) throws SQLException{ OracleCachedRowSet ocrs = new OracleCachedRowSet(); ocrs.populate(rs); return ocrs; }
}
|