一個(gè)新的Pageable接口及其實(shí)現
很顯然,看過(guò)上面三種實(shí)現方法后,我們對新的分頁(yè)機制有了一個(gè)目標,即:不與具體數據庫相關(guān);盡可能做到代碼重用;盡可能與原JDBC接口的使用方法保持一致;盡可能高的效率。
首先,我們需要提供一個(gè)與java.sql.ResultSet向下兼容的接口,把它命名為Pageable,接口定義如下:
public interface Pageable extends java.sql.ResultSet{
/**返回總頁(yè)數
*/
int getPageCount();
/**返回當前頁(yè)的記錄條數
*/
int getPageRowsCount();
/**返回分頁(yè)大小
*/
int getPageSize();
/**轉到指定頁(yè)
*/
void gotoPage(int page) ;
/**設置分頁(yè)大小
*/
void setPageSize(int pageSize);
/**返回總記錄行數
*/
int getRowsCount();
/**
* 轉到當前頁(yè)的第一條記錄
* @exception java.sql.SQLException 異常說(shuō)明。
*/
void pageFirst() throws java.sql.SQLException;
/**
* 轉到當前頁(yè)的最后一條記錄
* @exception java.sql.SQLException 異常說(shuō)明。
*/
void pageLast() throws java.sql.SQLException;
/**返回當前頁(yè)號
*/
int getCurPage();
}
這是一個(gè)對java.sql.ResultSet進(jìn)行了擴展的接口,主要是增加了對分頁(yè)的支持,如設置分頁(yè)大小,跳轉到某一頁(yè),返回總頁(yè)數等等。
接著(zhù),我們需要實(shí)現這個(gè)接口,由于這個(gè)接口繼承自ResultSet,并且它的大部分功能也都和ResultSet原有功能相同,所以這里使用了一個(gè)簡(jiǎn)單的Decorator模式。
PageableResultSet2的類(lèi)聲明和成員聲明如下:
public class PageableResultSet2 implements Pageable {
protected java.sql.ResultSet rs=null;
protected int rowsCount;
protected int pageSize;
protected int curPage;
protected String command = "";
}
可以看到,在PageableResultSet2中,包含了一個(gè)ResultSet的實(shí)例(這個(gè)實(shí)例只是實(shí)現了ResultSet接口,事實(shí)上它是由各個(gè)數據庫廠(chǎng)商分別實(shí)現的),并且把所有由ResultSet繼承來(lái)的方法都直接轉發(fā)給該實(shí)例來(lái)處理。
PageableResultSet2中繼承自ResultSet的主要方法:
//……
public boolean next() throws SQLException {
return rs.next();
}
//……
public String getString(String columnName) throws SQLException {
try {
return rs.getString(columnName);
}
catch (SQLException e) {//這里是為了增加一些出錯信息的內容便于調試
throw new SQLException (e.toString()+" columnName="
+columnName+"\r\nSQL="+this.getCommand());
}
}
//……
只有在Pageable接口中新增的方法才需要自己的寫(xiě)方法處理。
/**方法注釋可參考Pageable.java
*/
public int getCurPage() {
return curPage;
}
public int getPageCount() {
if(rowsCount==0) return 0;
if(pageSize==0) return 1;
//calculate PageCount
double tmpD=(double)rowsCount/pageSize;
int tmpI=(int)tmpD;
if(tmpD>tmpI) tmpI++;
return tmpI;
}
public int getPageRowsCount() {
if(pageSize==0) return rowsCount;
if(getRowsCount()==0) return 0;
if(curPage!=getPageCount()) return pageSize;
return rowsCount-(getPageCount()-1)*pageSize;
}
public int getPageSize() {
return pageSize;
}
public int getRowsCount() {
return rowsCount;
}
public void gotoPage(int page) {
if (rs == null)
return;
if (page < 1)
page = 1;
if (page > getPageCount())
page = getPageCount();
int row = (page - 1) * pageSize + 1;
try {
rs.absolute(row);
curPage = page;
}
catch (java.sql.SQLException e) {
}
}
public void pageFirst() throws java.sql.SQLException {
int row=(curPage-1)*pageSize+1;
rs.absolute(row);
}
public void pageLast() throws java.sql.SQLException {
int row=(curPage-1)*pageSize+getPageRowsCount();
rs.absolute(row);
}
public void setPageSize(int pageSize) {
if(pageSize>=0){
this.pageSize=pageSize;
curPage=1;
}
}
PageableResultSet2的構造方法:
public PageableResultSet2(java.sql.ResultSet rs) throws java.sql.SQLException {
if(rs==null) throw new SQLException("given ResultSet is NULL","user");
rs.last();
rowsCount=rs.getRow();
rs.beforeFirst();
this.rs=rs;
}
這里只是簡(jiǎn)單的取得一個(gè)總記錄數,并將記錄游標移回初始位置(before first),同時(shí)將參數中的ResultSet賦給成員變量。
Pageable的使用方法
因為Pageable接口繼承自ResultSet,所以在使用方法上與ResultSet一致,尤其是在不需要分頁(yè)功能的時(shí)候,可以直接當成ResultSet使用。而在需要分頁(yè)時(shí),只需要簡(jiǎn)單的setPageSize, gotoPage,即可。
PreparedStatement pstmt=null;
Pageable rs=null;
……//構造SQL,并準備一個(gè)pstmt.
rs=new PageableResultSet2(pstmt.executeQuery());//構造一個(gè)Pageable
rs.setPageSize(20);//每頁(yè)20個(gè)記錄
rs.gotoPage(2);//跳轉到第2頁(yè)
for(int i=0; i<rs.getPageRowsCount(); i++){//循環(huán)處理
int id=rs.getInt(“ID”);
……//繼續處理
}
總結
一個(gè)好的基礎類(lèi)應該是便于使用,并且具備足夠的可移植性,同時(shí)要保證其功能的完善。在上面的實(shí)現中,我們從java.sql.ResultSet接口繼承出Pageable,并實(shí)現了它。這就保證了在使用中與JDBC原有操作的一致性,同時(shí)對原有功能沒(méi)有縮減。同時(shí)它也是易于使用的,因為封裝了一切必要的操作,所以在你的代碼中唯一顯得"難看"和"不舒服"的地方就是需要自己去構造一個(gè)PageableResultSet2。不過(guò)只要你愿意,這也是可以解決的。當然它也有具有充分的可移植性,當你將數據庫由Oracle變?yōu)镸ysql或者SQLServer的時(shí)候,你仍然可以使用這些分頁(yè)的代碼。它在使用中(或者說(shuō)在移植的過(guò)程中)唯一的限制就是你必須要使用一個(gè)支持JDBC2的驅動(dòng)(現在明白為什么我把類(lèi)命名為PageableResultSet2了吧。:P),不過(guò),好在JDBC2已經(jīng)成為標準了,絕大多數的數據庫(如Oracle, Mysql, SQLServer)都有自己的或者第三方提供的JDBC2的驅動(dòng)。
OK,這個(gè)分頁(yè)的實(shí)現是否對你的編程有幫助呢?仔細看看,其實(shí)真正自己寫(xiě)的代碼并不多的,大部分都只是簡(jiǎn)單的轉發(fā)操作。一個(gè)合適的模式應用可以幫你很大忙。
聯(lián)系客服