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