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