存儲過程分頁查詢

相信大家都遇到過數據的分頁查詢,其實就是將過多的結果在有限的界面上分好多頁來顯示,這個是很多網站常用的功能,也是最基本的功能,今天就做個簡單總結。

一般人們將分頁查詢分爲兩類:邏輯分頁,物理分頁,我們先從理論上理解一下:
1、物理分頁:
物理分頁概述:使用數據庫自身所帶的分頁機制,例如,Oracle數據庫的rownum,或者Mysql數據庫中的limit等機制來完成分頁操作。因爲是對數據庫實實在在的數據進行分頁條件查詢,所以叫物理分頁。每一次物理分頁都會去連接數據庫。
優點:數據能夠保證最新,由於根據分頁條件會查詢出少量的數據,所以不會佔用太多的內存。
缺點:物理分頁使用了數據庫自身帶的機制,所以這樣的SQL語句不通用,導致不能進行數據庫的移植。

2、邏輯分頁:
邏輯分頁利用遊標分頁,好處是所有數據庫都統一,壞處就是效率低。
邏輯分頁概述:就是用戶第一次訪問時,將數據庫的所有記錄全部查詢出來,添加到一個大的集合中,然後存放在session對象,然後通過頁碼計算出當前頁需要顯示的數據內容,存儲到一個小的list的集合中,並將之存儲到request對象中,跳轉到JSP頁面,進行遍歷顯示。 當用戶第二次訪問時,只要不關閉瀏覽器,我們還會從session中獲取數據,來進行顯示。爲什麼叫邏輯分頁呢?因爲此種方法是在內存的session對象中進行計算分頁顯示的,而不是真正的將我們數據庫進行分頁的。

來看它的一些缺點吧:
a,如果需要查詢的數據量過大,session將耗費大量的內存;
b,因爲是在session中獲取數據,如果第二次或者更多此的不關閉瀏覽器訪問,會直接訪問session,從而不能保證數據是最新的。

    小結:這種分頁很少使用。但是在數據量小,不會被修改的數據,使用邏輯分頁會提高程序的執行效率。

3、常用orm框架採用的分頁技術:

①:hibernate採用的是物理分頁;
②:MyBatis使用RowBounds實現的分頁是邏輯分頁,也就是先把數據記錄全部查詢出來,然在再根據offset和limit截斷記錄返回(數據量大的時候會造成內存溢出),不過可以用插件或其他方式能達到物理分頁效果。

mybatis的物理分頁插件:常見的兩種: Mybatis-Paginator Mybatis-PageHelper

爲了在數據庫層面上實現物理分頁,又不改變原來MyBatis的函數邏輯,可以編寫plugin截獲MyBatis Executor的statementhandler,重寫SQL來執行查詢

小結:在實際中物理分頁還是使用的較多的,但現在有較多開發者使用開源的框架mybatis的分頁插件 PageHelper,進行分頁查詢。

Oracle存儲過程分頁查詢

第一步:這裏不再解釋package (不瞭解的可以看我之前寫的文章package詳細介紹)
create or replace package TESTPACKAGE as
type Test_CURSOR is ref cursor;
end TESTPACKAGE;

第二步:

create or replace procedure OraclePager
(
       tableName in varchar2, --表名
       fields in varchar2,    --查詢解果顯示字段: 字段1,字段2,..,字段n
       wherecase in varchar2, --查詢條件 
       pageSize in number,  --一頁顯示記錄數
       pageNow in number,   --當前頁
       orderField  varchar2, --排序字段,爲空表示不排序
       orderFlag number,     --排序標識 0:正序 1:倒序
       myrows out number,   --總記錄數
       myPageCount out number, --總分頁
       p_cursor out TESTPACKAGE.Test_CURSOR --返回的記錄集
) is  
--定義部分
--定義sql語句字符串
v_sql varchar2(8000);
--定義兩個整數
v_begin number:=(pageNow-1)*pagesize+1; --開始記錄
v_end number:=pageNow*pageSize;         --結束記錄
--排序sql
v_orderSql varchar2(100):='';
v_wherecase varchar2(1000):='';
begin
  --執行部分
  --如果orderField不爲空,則進行排序,如果orderFlag=0爲升序,1爲降序
  if orderField is not null then
    if orderFlag=0 then
      v_orderSql:=' order by '||orderField; --正序
    elsif orderFlag=1 then
      v_orderSql:=' order by '||orderField||' desc';--倒序
    else
      null;
    end if;
  end if;
  --條件判斷語句
  if wherecase is not null then
    v_wherecase:=' where '||wherecase;
  end if;
  --判斷是不是超出索引
  --計算myrows和myPageCount
  --組織一個sql
  v_sql:='select count(*) from '|| tableName || v_wherecase;
  --dbms_output.put_line('count='||v_sql);
  --執行sql,並把返回的值賦給myrows;
  execute immediate v_sql into myrows;
  --計算myPageCount分頁數
  if mod(myrows,Pagesize)=0 then--Oracle mod(number1,number2)返回的值爲其餘數值
    myPageCount:=myrows/Pagesize;
  else
    myPageCount:=trunc(myrows/pagesize)+1;--Oracle trunc(number)可以對傳入值進行四捨五入
  end if;
  if pageNow>mypageCount then
  v_begin:=(mypageCount-1)*pagesize+1; --開始記錄
  v_end:=mypageCount*pageSize;       --結束記錄
  end if;

  v_sql:='select * from
          (select t1.* ,rownum rn from(select '|| fields ||' from '|| tableName|| v_wherecase ||' '||v_orderSql ||') t1 where rownum<='|| v_end ||')
          where rn>='|| v_begin;
  --把遊標和sql關聯
  open p_cursor for v_sql;
  --關閉遊標
  --close p_cursor;
end OraclePager;

第三步:測試代碼

public static void main(String[] args) throws SQLException {
        Statement stmt = null;
        ResultSet rs = null;
        Connection conn = null;
        try {
            Class.forName(driver);
            conn = DriverManager.getConnection(url, name, password);
            CallableStatement proc = null;
            proc = conn.prepareCall("{ call OraclePager(?,?,?,?,?,?,?,?,?,?) }"); // 設置存儲過程
            proc.setString(1, "tab_1");// 表名
            proc.setString(2, "id,name,password");// 查詢解果顯示字段: 字段1,字段2,..,字段n
            proc.setString(3, "");// 查詢條件 
            proc.setInt(4, 10);// 一頁顯示記錄數
            proc.setInt(5, 1);// 當前頁碼
System.out.println("當前頁碼 : 1" );
            proc.setString(6, "");// 排序字段,爲空表示不排序
            proc.setString(7, "");// 排序標識 0:正序 1:倒序
            proc.registerOutParameter(8, oracle.jdbc.OracleTypes.NUMBER);// 總記錄數
            proc.registerOutParameter(9, oracle.jdbc.OracleTypes.NUMBER);// 總分頁
            proc.registerOutParameter(10, oracle.jdbc.OracleTypes.CURSOR);// 返回的記錄集(相當於List集合)
            proc.execute();// 執行
            String myrows = proc.getString(8);// 輸出總記錄數
            String myPageCount = proc.getString(9);// 總分頁
            System.out.println("總記錄數 : " + myrows);
            System.out.println("總分頁 : " + myPageCount);
            rs = (ResultSet) proc.getObject(10);
            while (rs.next()) {
                System.out.println(
                        " ID:  " + rs.getString(1) + "  名字:  " + rs.getString(2) + "  密碼:  " + rs.getString(3));
            }


        } catch (SQLException ex2) {
            ex2.printStackTrace();
        } catch (Exception ex2) {
            ex2.printStackTrace();
        } finally {
            try {
                if (rs != null) {
                    rs.close();
                    if (stmt != null) {
                        stmt.close();
                    }
                    if (conn != null) {
                        conn.close();
                    }
                }
            } catch (Exception e) {

            }
        }
    }

查詢第一頁運行結果:

當前頁碼 : 1
總記錄數 : 10000
總 分 頁 : 1000
ID:7135 名字: 新增用戶7135 密碼:[email protected]
ID:7136 名字: 新增用戶7136 密碼:[email protected]
ID:7137 名字: 新增用戶7137 密碼:[email protected]
ID:7138 名字: 新增用戶7138 密碼:[email protected]
ID:7139 名字: 新增用戶7139 密碼:[email protected]
ID:7140 名字: 新增用戶7140 密碼:[email protected]
ID:7141 名字: 新增用戶7141 密碼:[email protected]
ID:7142 名字: 新增用戶7142 密碼:[email protected]
ID:7143 名字: 新增用戶7143 密碼:[email protected]
ID:7144 名字: 新增用戶7144 密碼:[email protected]

查詢第二頁運行結果:

當前頁碼 : 2
總記錄數 : 10000
總 分 頁 : 1000
ID:7145 名字: 新增用戶7145 密碼:[email protected]
ID:7146 名字: 新增用戶7146 密碼:[email protected]
ID:7147 名字: 新增用戶7147 密碼:[email protected]
ID:7148 名字: 新增用戶7148 密碼:[email protected]
ID:7149 名字: 新增用戶7149 密碼:[email protected]
ID:7150 名字: 新增用戶7150 密碼:[email protected]
ID:7151 名字: 新增用戶7151 密碼:[email protected]
ID:7152 名字: 新增用戶7152 密碼:[email protected]
ID:7153 名字: 新增用戶7153 密碼:[email protected]
ID:7154 名字: 新增用戶7154 密碼:[email protected]

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章