JDBC分頁工具類
不知道大家做項目做到最后有什么感覺沒有,其實大家做來做去就是做一個列表加上分頁和多條件的查詢,只是不同的項目業務流程不一樣而已,所以今天我想說說這里的分頁。
1、 大家需要了解的是為什么我們需要分頁?
因為當數據量太大時,會影響查詢和傳輸的性能,并且我們從用戶角度來考慮的話,如果讓用戶一次性看到成千上萬條記錄那用戶也會瘋掉的。
2、 對我們來說有哪些可實現的分頁技術?
a、 存儲過程分頁,即在數據庫中創建一個存儲過程,傳入SQL和頁碼獲取當前頁的記錄,這個需要大家對存儲過程有比較好的認識(我這塊不行),當然這個從性能上來說是最好的,但是不能跨數據庫平臺。
b、 使用數據庫專有SQL語句進行分頁(Oracle的rownum、MSSQL的top、MySql的limit等),性能也很好,但是還是不能跨數據庫(其實真實項目中沒那么多項目要求都跨數據庫)。
c、 JDBC分頁,通過Statement的statement.setMaxRow(endIndex)和resultSet.absoulte(beginIndex)取得當前頁范圍內的記錄。此種方式的性能依賴于廠商對JDBC規范的實現。這種方式的通用性是最好的,性能也不錯,完全與數據庫平臺無關了。
d、 根據數據庫類型自動生成數據庫專有特性的sql語句,其實說白了也就是Hibernate的實現方式,這個自己也寫過一個,其實就是根據數據庫類型生成不同的數據庫SQL專有語句而已。
下面我們需要寫一個分頁工具類,在寫之前我們需要弄明白分頁的原理。為了能夠取得指定頁碼所對應的記錄,我們是不是需要兩個關鍵的參數:總記錄數和每頁的記錄數;
每頁的記錄數我們可以設置一個默認值,10、15、20、25都無所謂,根據實際需求。
總記錄數就沒辦法了,需要額外從數據庫中利用Count函數取了,通過這兩個參數我們是不是可以計算出總頁數。同時我們也可以判斷用戶傳過來的頁碼是否有效(小于第一頁OR超出最后一頁),然后我們再根據頁碼和每頁記錄數是不是就可以計算出當前頁的的開始條數和終止條數了。
下面我們就需要來看看分頁的工具類了
package com.iflytek.page; /** * 分頁工具類 * * @author xudongwang 2012-1-19 * * Email:xdwangiflytek@gmail.com */ public class Page { /** * 總記錄數 */ private int totalRow; /** * 每頁記錄數 */ private int pageSize = 10; /** * 當前頁碼 */ private int currentCount; /** * 總頁數 */ private int total; /** * 起始記錄下標 */ private int beginIndex; /** * 截止記錄下標 */ private int endIndex; /** * 構造方法,使用總記錄數,當前頁碼 * * @param totalRow * 總記錄數 * @param currentCount * 當前頁面,從1開始 */ public Page(int totalRow, int currentCount) { this.totalRow = totalRow; this.currentCount = currentCount; calculate(); } /** * 構造方法 ,利用總記錄數,當前頁面 * * @param totalRow * 總記錄數 * @param currentCount * 當前頁面 * @param pageSize * 默認10條 */ public Page(int totalRow, int currentCount, int pageSize) { this.totalRow = totalRow; this.currentCount = currentCount; this.pageSize = pageSize; calculate(); } private void calculate() { total = totalRow / pageSize + ((totalRow % pageSize) > 0 ? 1 : 0); if (currentCount > total) { currentCount = total; } else if (currentCount < 1) { currentCount = 1; } beginIndex = (currentCount - 1) * pageSize; endIndex = beginIndex + pageSize; if (endIndex > totalRow) { endIndex = totalRow; } } public int getTotalRow() { return totalRow; } public int getPageSize() { return pageSize; } public int getCurrentCount() { return currentCount; } public int getTotal() { return total; } public int getBeginIndex() { return beginIndex; } public int getEndIndex() { return endIndex; } }
繼續
在后臺獲取前臺傳進來的頁碼 //從頁面取得頁碼
int currentPage = 1; try { currentPage = Integer.parseInt(request.getParameter("currentPage")); } catch (Exception ex) {} //取得總記錄數,創建Page對象 int totalRow = studentDao.getAllStudents();//通過select count 取得總記錄數 Page page = new Page(totalRow, currentPage); studentDao.list(page);數據訪問層, StduentDao.java
public List<Stduent> getStudentsByPage(Page page) { List<Stduent> students = new ArrayList<Stduent>(); try { String sql = "SELECT id,name,email FROM tbl_stduent"; Connection conn = null; try { conn = DbUtil.getConnection(); Statement statement = conn.createStatement(); statement.setMaxRows(page.getEndIndex());//關鍵代碼,設置最大記錄數為當前頁記錄的截止下標 ResultSet resultSet = statement.executeQuery(sql); if (page.getBeginIndex() > 0) { resultSet.absolute(page.getBeginIndex());//關鍵代碼,直接移動游標為當前頁起始記錄處 } while (resultSet.next()) { Stduent student = new Student(); …… students.add(student); } resultSet.close(); statement.close(); } finally { if (conn != null) { conn.close(); } } } catch (SQLException e) { e.printStackTrace(); } return students; }其實仔細想想 JDBC 分頁的性能與頁碼有關即與 statement.setMaxRows 有效,越往后翻,性能越差,因為越往后一次性查詢的記錄數就多,但是我們從用戶的角度來看不會有用戶會牛逼的一頁一頁翻到第 n 頁去,一般都是根據條件來縮小查詢范圍。所以折中的辦法就是將記錄數設大一點,另外就是限制用戶翻頁的范圍,其實這些性能的前提都是在數據量非常大的情況下而言的,一般數據量少的話,基本上都可以忽略不計的。
來自:http://xdwangiflytek.iteye.com/blog/1358080