前言
在使用數據庫的過(guò)程中,不可避免的需要使用到分頁(yè)的功能,可是JDBC的規范對此卻沒(méi)有很好的解決。對于這個(gè)需求很多朋友都有自己的解決方案,比如使用Vector等集合類(lèi)先保存取出的數據再分頁(yè)。但這種方法的可用性很差,與JDBC本身的接口完全不同,對不同類(lèi)型的字段的支持也不好。這里提供了一種與JDBC兼容性非常好的方案。
JDBC和分頁(yè)
Sun的JDBC規范的制定,有時(shí)很讓人哭笑不得,在JDBC1.0中,對于一個(gè)結果集(ResultSet)你甚至只能執行next()操作,而無(wú)法讓其向后滾動(dòng),這就直接導致在只執行一次SQL查詢(xún)的情況下無(wú)法獲得結果集的大小。所以,如果你使用的是JDBC1.0的驅動(dòng),那么是幾乎無(wú)法實(shí)現分頁(yè)的。
好在Sun的JDBC2規范中很好的彌補了這一個(gè)不足,增加了結果集的前后滾動(dòng)操作,雖然仍然不能直接支持分頁(yè),但我們已經(jīng)可以在這個(gè)基礎上寫(xiě)出自己的可支持分頁(yè)的ResultSet了。
和具體數據庫相關(guān)的實(shí)現方法
有一些數據庫,如Mysql, Oracle等有自己的分頁(yè)方法,比如Mysql可以使用limit子句,Oracle可以使用ROWNUM來(lái)限制結果集的大小和起始位置。這里以Mysql為例,其典型代碼如下:
// 計算總的記錄條數
String SQL = "SELECT Count(*) AS total " + this.QueryPart;
rs = db.executeQuery(SQL);
if (rs.next())
Total = rs.getInt(1);
// 設置當前頁(yè)數和總頁(yè)數
TPages = (int)Math.ceil((double)this.Total/this.MaxLine);
CPages = (int)Math.floor((double)Offset/this.MaxLine+1);
// 根據條件判斷,取出所需記錄
if (Total > 0) {
SQL = Query + " LIMIT " + Offset + " , " + MaxLine;
rs = db.executeQuery(SQL);
}
return rs;
}
毫無(wú)疑問(wèn),這段代碼在數據庫是Mysql時(shí)將會(huì )是漂亮的,但是作為一個(gè)通用的類(lèi)(事實(shí)上我后面要提供的就是一個(gè)通用類(lèi)庫中的一部分),需要適應不同的數據庫,而基于這個(gè)類(lèi)(庫)的應用,也可能使用不同的數據庫,所以,我們將不使用這種方法。
另一種繁瑣的實(shí)現方法
我看過(guò)一些人的做法(事實(shí)上包括我在內,一開(kāi)始也是使用這種方法的),即不使用任何封裝,在需要分頁(yè)的地方,直接操作ResultSet滾到相應的位置,再讀取相應數量的記錄
。其典型代碼如下:
<%
sqlStmt = sqlCon.createStatement(java.sql.ResultSet.TYPE_SCROLL_INSENSITIVE,
java.sql.ResultSet.CONCUR_READ_ONLY);
strSQL = "select name,age from test";
//執行SQL語(yǔ)句并獲取結果集
sqlRst = sqlStmt.executeQuery(strSQL);
//獲取記錄總數
sqlRst.last();
intRowCount = sqlRst.getRow();
//記算總頁(yè)數
intPageCount = (intRowCount+intPageSize-1) / intPageSize;
//調整待顯示的頁(yè)碼
if(intPage>intPageCount) intPage = intPageCount;
%>
<table border="1" cellspacing="0" cellpadding="0">
<tr>
<th>姓名</th>
<th>年齡</th>
</tr>
<%
if(intPageCount>0){
//將記錄指針定位到待顯示頁(yè)的第一條記錄上
sqlRst.absolute((intPage-1) * intPageSize + 1);
//顯示數據
i = 0;
while(i<intPageSize && !sqlRst.isAfterLast()){
%>
<tr>
<td><%=sqlRst.getString(1)%></td>
<td><%=sqlRst.getString(2)%></td>
</tr>
<%
sqlRst.next();
i++;
}
}
%>
</table>
很顯然,這種方法沒(méi)有考慮到代碼重用的問(wèn)題,不僅代碼數量巨大,而且在代碼需要修改的情況下,將會(huì )無(wú)所適從。
使用Vector進(jìn)行分頁(yè)
還見(jiàn)過(guò)另一些實(shí)現分頁(yè)的類(lèi),是先將所有記錄都select出來(lái),然后將ResultSet中的數據都get出來(lái),存入Vector等集合類(lèi)中,再根據所需分頁(yè)的大小,頁(yè)數,定位到相應的位置,讀取數據?;蛘呦仁褂们懊嫣岬降膬煞N分頁(yè)方法,取得所需的頁(yè)面之后,再存入Vector中。扔開(kāi)代碼的效率不說(shuō),單是從程序結構和使用的方便性上講,就是很糟糕的。比如,這種做法支持的字段類(lèi)型有限,int, double, String類(lèi)型還比較好處理,如果碰到Blob, Text等類(lèi)型,實(shí)現起來(lái)就很麻煩了。這是一種更不可取的方案。 前言
在使用數據庫的過(guò)程中,不可避免的需要使用到分頁(yè)的功能,可是JDBC的規范對此卻沒(méi)有很好的解決。對于這個(gè)需求很多朋友都有自己的解決方案,比如使用Vector等集合類(lèi)先保存取出的數據再分頁(yè)。但這種方法的可用性很差,與JDBC本身的接口完全不同,對不同類(lèi)型的字段的支持也不好。這里提供了一種與JDBC兼容性非常好的方案。
JDBC和分頁(yè)
Sun的JDBC規范的制定,有時(shí)很讓人哭笑不得,在JDBC1.0中,對于一個(gè)結果集(ResultSet)你甚至只能執行next()操作,而無(wú)法讓其向后滾動(dòng),這就直接導致在只執行一次SQL查詢(xún)的情況下無(wú)法獲得結果集的大小。所以,如果你使用的是JDBC1.0的驅動(dòng),那么是幾乎無(wú)法實(shí)現分頁(yè)的。
好在Sun的JDBC2規范中很好的彌補了這一個(gè)不足,增加了結果集的前后滾動(dòng)操作,雖然仍然不能直接支持分頁(yè),但我們已經(jīng)可以在這個(gè)基礎上寫(xiě)出自己的可支持分頁(yè)的ResultSet了。
和具體數據庫相關(guān)的實(shí)現方法
有一些數據庫,如Mysql, Oracle等有自己的分頁(yè)方法,比如Mysql可以使用limit子句,Oracle可以使用ROWNUM來(lái)限制結果集的大小和起始位置。這里以Mysql為例,其典型代碼如下:
// 計算總的記錄條數
String SQL = "SELECT Count(*) AS total " + this.QueryPart;
rs = db.executeQuery(SQL);
if (rs.next())
Total = rs.getInt(1);
// 設置當前頁(yè)數和總頁(yè)數
TPages = (int)Math.ceil((double)this.Total/this.MaxLine);
CPages = (int)Math.floor((double)Offset/this.MaxLine+1);
// 根據條件判斷,取出所需記錄
if (Total > 0) {
SQL = Query + " LIMIT " + Offset + " , " + MaxLine;
rs = db.executeQuery(SQL);
}
return rs;
}
毫無(wú)疑問(wèn),這段代碼在數據庫是Mysql時(shí)將會(huì )是漂亮的,但是作為一個(gè)通用的類(lèi)(事實(shí)上我后面要提供的就是一個(gè)通用類(lèi)庫中的一部分),需要適應不同的數據庫,而基于這個(gè)類(lèi)(庫)的應用,也可能使用不同的數據庫,所以,我們將不使用這種方法。
另一種繁瑣的實(shí)現方法
我看過(guò)一些人的做法(事實(shí)上包括我在內,一開(kāi)始也是使用這種方法的),即不使用任何封裝,在需要分頁(yè)的地方,直接操作ResultSet滾到相應的位置,再讀取相應數量的記錄
。其典型代碼如下:
<%
sqlStmt = sqlCon.createStatement(java.sql.ResultSet.TYPE_SCROLL_INSENSITIVE,
java.sql.ResultSet.CONCUR_READ_ONLY);
strSQL = "select name,age from test";
//執行SQL語(yǔ)句并獲取結果集
sqlRst = sqlStmt.executeQuery(strSQL);
//獲取記錄總數
sqlRst.last();
intRowCount = sqlRst.getRow();
//記算總頁(yè)數
intPageCount = (intRowCount+intPageSize-1) / intPageSize;
//調整待顯示的頁(yè)碼
if(intPage>intPageCount) intPage = intPageCount;
%>
| 姓名 | 年齡 |
|---|---|
| <%=sqlRst.getString(1)%> | <%=sqlRst.getString(2)%> |
使用Vector進(jìn)行分頁(yè)
還見(jiàn)過(guò)另一些實(shí)現分頁(yè)的類(lèi),是先將所有記錄都select出來(lái),然后將ResultSet中的數據都get出來(lái),存入Vector等集合類(lèi)中,再根據所需分頁(yè)的大小,頁(yè)數,定位到相應的位置,讀取數據?;蛘呦仁褂们懊嫣岬降膬煞N分頁(yè)方法,取得所需的頁(yè)面之后,再存入Vector中。扔開(kāi)代碼的效率不說(shuō),單是從程序結構和使用的方便性上講,就是很糟糕的。比如,這種做法支持的字段類(lèi)型有限,int, double, String類(lèi)型還比較好處理,如果碰到Blob, Text等類(lèi)型,實(shí)現起來(lái)就很麻煩了。這是一種更不可取的方案。
聯(lián)系客服