分頁查詢

分頁查詢,就是將將過多的結果在有限的界面上分好多頁來顯示,這個是很多網站常用的功能,也是最基本的功能,今天簡單總結一下。


          分頁以前聽人們說都是一項技術,但是我覺的不盡然。我認爲分頁是將數據庫的數據,利用一些特殊的sql語句來進行查詢,顯示理所應當顯示的內容,更恰當的說可以是對SQL語句的靈活運用,對邏輯思維的簡單使用。


         一,一般人們將分頁查詢分爲兩類:邏輯分頁,物理分頁,我們先從理論上理解一下:

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

        來看它的一些缺點吧:

              a,如果需要查詢的數據量過大,session將耗費大量的內存;

              b,因爲是在session中獲取數據,如果第二次或者更多此的不關閉瀏覽器訪問,會直接訪問session,從而不能保證數據是最新的。

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

 

           2,物理分頁概述:使用數據庫自身所帶的分頁機制,例如,Oracle數據庫的rownum,或者Mysql數據庫中的limit等機制來完成分頁操作。因爲是對數據庫實實在在的數據進行分頁條件查詢,所以叫物理分頁。每一次物理分頁都會去連接數據庫。

            優點:數據能夠保證最新,由於根據分頁條件會查詢出少量的數據,所以不會佔用太多的內存。

            缺點:物理分頁使用了數據庫自身帶的機制,所以這樣的SQL語句不通用,導致不能進行數據庫的移植。

           小結:在實際中物理分頁還是使用的較多的。

 


  二,看一下邏輯分頁查詢的應用:


[java] view plain copy
 print?在CODE上查看代碼片派生到我的代碼片
  1. <span style="font-size:18px;">  public class PageQueryUserServlet extends HttpServlet {  
  2.       
  3.         @Override  
  4.         protected void doGet(HttpServletRequest request, HttpServletResponse response)  
  5.                 throws ServletException, IOException {  
  6.               
  7.             //獲取頁碼  
  8.             int pageno = Integer.parseInt(request.getParameter("pageno")==null?"1":request.getParameter("pageno"));   
  9.               
  10.               
  11.             //從session中獲取大List集合  
  12.             HttpSession session = request.getSession();  
  13.             List<User> bigList = (List<User>)session.getAttribute("bigList");  
  14.               
  15.             //如果第一次訪問  
  16.             if(bigList == null){  
  17.                   
  18.                 //創建大List集合  
  19.                 bigList = new ArrayList<User>();  
  20.                   
  21.                 //如果大List集合不存在,則連接數據庫  
  22.                 Connection conn = null;  
  23.                 PreparedStatement ps= null;  
  24.                 ResultSet rs = null;  
  25.                 try {  
  26.                     conn = DBUtil.getConnection();  
  27.                     String sql = "select usercode,username,orgtype from t_user order by regdate desc";  
  28.                     ps = conn.prepareStatement(sql);  
  29.                       
  30.                     //執行查詢語句返回查詢結果集  
  31.                     rs = ps.executeQuery();  
  32.                       
  33.                     //遍歷結果集封裝javabean對象並存儲到大List集合中  
  34.                     while(rs.next()){  
  35.                         User user = new User();  
  36.                         user.setUsercode(rs.getString("usercode"));  
  37.                         user.setUsername(rs.getString("username"));  
  38.                         user.setOrgtype(rs.getString("orgtype"));  
  39.                         bigList.add(user);  
  40.                     }  
  41.                       
  42.                     //將大List集合存儲到session中  
  43.                     session.setAttribute("bigList", bigList);  
  44.                       
  45.                 } catch (Exception e) {  
  46.                     e.printStackTrace();  
  47.                 } finally{  
  48.                     DBUtil.close(conn, ps, rs);  
  49.                 }  
  50.             }  
  51.               
  52.               
  53.             //如果從session中可以獲取到大List集合,則通過頁碼計算得出小List集合  
  54.             List<User> smallList = new ArrayList<User>();  
  55.               
  56.             //計算開始標識=頁數大小*(頁碼-1)  
  57.             int beginIndex = Const.PAGE_SIZE * (pageno-1);  
  58.               
  59.             //結束標識=頁數大小*頁碼,如果超過了總數據條數,則表示爲最後一頁,寫爲總結條數即可  
  60.             int endIndex = Const.PAGE_SIZE * pageno > bigList.size() ? bigList.size() : Const.PAGE_SIZE * pageno;  
  61.               
  62.             for(int i=beginIndex;i<endIndex;i++){  
  63.                 smallList.add(bigList.get(i));  
  64.             }  
  65.               
  66.             //將小List集合存儲到request對象中  
  67.             request.setAttribute("userList", smallList);  
  68.               
  69.             //轉發  
  70.         }  
  71.           
  72.   
  73. }</span>  



          三,好,物理分頁和邏輯分頁的計算方法差不多,只不過一個是session中一個是在數據庫中,這裏物理分頁總結一下多條件查詢分頁顯示的過程,這裏也將分頁對象進行封裝了:

            先看一下分頁對象的編寫:

[java] view plain copy
 print?在CODE上查看代碼片派生到我的代碼片
  1. <span style="font-size:18px;">  /** 
  2.      * 分頁對象 
  3.      * @author Administrator 
  4.      */  
  5.     public class Page<T> {  
  6.         /** 
  7.          * 頁碼 
  8.          */  
  9.         private int pageno;  
  10.           
  11.         /** 
  12.          * 每頁顯示的記錄條數 
  13.          */  
  14.         private int pagesize;  
  15.           
  16.         /** 
  17.          * 數據集合(需要顯示在網頁中的數據) 
  18.          */  
  19.         private List<T> dataList;  
  20.           
  21.         /** 
  22.          * 總記錄條數 
  23.          */  
  24.         private int totalsize;  
  25.           
  26.           
  27.         public Page(String pageno) {  
  28.             this.pageno = (pageno == null ? 1 : Integer.parseInt(pageno));  
  29.             this.pagesize = Const.PAGE_SIZE;  
  30.             this.dataList = new ArrayList<T>();  
  31.         }  
  32.           
  33.         public int getPageno(){  
  34.             return pageno;  
  35.         }  
  36.           
  37.         public int getPagesize(){  
  38.             return pagesize;  
  39.         }  
  40.           
  41.         public List<T> getDataList(){  
  42.             return dataList;  
  43.         }  
  44.           
  45.         public void setTotalsize(int totalsize){  
  46.             this.totalsize = totalsize;  
  47.         }  
  48.           
  49.         public int getTotalsize(){  
  50.             return totalsize;  
  51.         }  
  52.           
  53.         public int getPagecount(){  
  54.             return totalsize%pagesize == 0 ? totalsize/pagesize : totalsize/pagesize + 1;  
  55.         }  
  56.           
  57.         /** 
  58.          * 通過業務SQL語句獲取分頁SQL語句 
  59.          * @param sql 業務SQL 
  60.          * @return 分頁SQL語句 
  61.          * 這是非常核心的,通過多次嵌套,嵌套出分頁sql語句的編寫 
  62.          */  
  63.         public String getSql(String sql){  
  64.             return "select t1.* from (select t.*,rownum as linenum from ("+sql+") t where rownum<=" + pageno*pagesize + ") t1 where t1.linenum>" + (pageno-1)*pagesize;  
  65.         }  
  66.     }  
  67. </span>  

 有了這個分頁對象,我就可以利用它了,看我們動態參數分頁查詢的過程,重點看註釋步驟:

[java] view plain copy
 print?在CODE上查看代碼片派生到我的代碼片
  1. <span style="font-size:18px;">  /** 
  2.      * 動態參數查詢,難度最大的是SQL語句動態拼接。(因爲查詢提交內容不定,查詢提交個數不定) 
  3.      * @author Administrator 
  4.      */  
  5.     public class PageQueryInvServlet extends HttpServlet {  
  6.       
  7.         @Override  
  8.         protected void doPost(HttpServletRequest request, HttpServletResponse response)  
  9.                 throws ServletException, IOException {  
  10.               
  11.             //解決請求體的中文亂碼問題  
  12.             //request.setCharacterEncoding("GB18030");  
  13.               
  14.             //創建分頁對象  
  15.             Page<Investor> page = new Page<Investor>(request.getParameter("pageno"));  
  16.               
  17.             //獲取查詢提交的數據  
  18.             String invregnum = request.getParameter("invregnum");  
  19.             String invname = request.getParameter("invname");  
  20.             String startdate = request.getParameter("startdate");  
  21.             String enddate = request.getParameter("enddate");  
  22.               
  23.             //拼接業務SQL,注意其中的技巧,where 1=1,另外這裏使用StringBuilder提高拼接的效率  
  24.             StringBuilder sql = new StringBuilder("select i.invregnum,i.invname,i.regdate,u.username,i.cty from t_invest i join t_user u on i.usercode=u.usercode where 1=1");  
  25.             StringBuilder totalsizeSql = new StringBuilder("select count(*) as totalsize from t_invest i join t_user u on i.usercode=u.usercode where 1=1");  
  26.             //創建list集合用來綁定下標和內容,利用的list下標和值對應關係的特點  
  27.             List<String> paramList = new ArrayList<String>();  
  28.               
  29.             //動態參數拼接動態SQL語句  
  30.             if(StringUtil.isNotEmpty(invregnum)){  
  31.                 sql.append(" and i.invregnum = ?");  
  32.                 totalsizeSql.append(" and i.invregnum = ?");  
  33.                 paramList.add(invregnum);   
  34.             }  
  35.               
  36.             if(StringUtil.isNotEmpty(invname)){  
  37.                 sql.append(" and i.invname like ?");  
  38.                 totalsizeSql.append(" and i.invname like ?");  
  39.                 paramList.add("%" + invname + "%");   
  40.             }  
  41.               
  42.             if(StringUtil.isNotEmpty(startdate)){  
  43.                 sql.append(" and i.regdate >= ?");  
  44.                 totalsizeSql.append(" and i.regdate >= ?");  
  45.                 paramList.add(startdate);   
  46.             }  
  47.               
  48.             if(StringUtil.isNotEmpty(enddate)){  
  49.                 sql.append(" and i.regdate <= ?");  
  50.                 totalsizeSql.append(" and i.regdate <= ?");  
  51.                 paramList.add(enddate);   
  52.             }  
  53.               
  54.             //調用獲取分頁SQL  
  55.             String pageSql = page.getSql(sql.toString());  
  56.               
  57.             //連接數據庫查詢數據  
  58.             Connection conn = null;  
  59.             PreparedStatement ps = null;  
  60.             ResultSet rs = null;  
  61.             try {  
  62.                 conn = DBUtil.getConnection();  
  63.                 ps = conn.prepareStatement(pageSql);  
  64.                   
  65.                 //給?賦值(重點),這裏list的巧妙使用  
  66.                 for(int i=0;i<paramList.size();i++){  
  67.                     ps.setString(i+1, paramList.get(i));  
  68.                 }  
  69.                   
  70.                 //執行查詢語句,返回查詢結果集  
  71.                 rs = ps.executeQuery();  
  72.                   
  73.                 //遍歷結果集,每遍歷一次,封裝Investor對象,將其添加到List集合中  
  74.                 while(rs.next()){  
  75.                     Investor inv = new Investor();  
  76.                     inv.setInvregnum(rs.getString("invregnum"));  
  77.                     inv.setInvname(rs.getString("invname"));  
  78.                     inv.setRegdate(rs.getString("regdate"));  
  79.                     inv.setUsername(rs.getString("username"));  
  80.                     inv.setCty(rs.getString("cty"));  
  81.                       
  82.                     page.getDataList().add(inv);  
  83.                 }  
  84.                   
  85.                 //查詢總記錄條數,並且設置到分頁對象中  
  86.                 ps = conn.prepareStatement(totalsizeSql.toString());  
  87.                   
  88.                 //給?賦值  
  89.                 for(int i=0;i<paramList.size();i++){  
  90.                     ps.setString(i+1, paramList.get(i));  
  91.                 }  
  92.                   
  93.                 rs = ps.executeQuery();  
  94.                   
  95.                 if(rs.next()){  
  96.                     page.setTotalsize(rs.getInt("totalsize"));  
  97.                 }  
  98.                   
  99.             } catch (Exception e) {  
  100.                 e.printStackTrace();  
  101.             } finally{  
  102.                 DBUtil.close(conn, ps, rs);  
  103.             }  
  104.               
  105.             //將分頁對象存儲到request範圍中  
  106.             request.setAttribute("pageObj", page);  
  107.               
  108.             //轉發  
  109.                
  110.         }  
  111.           
  112.     }  
  113. </span>  



          分頁查詢將數據量分成幾批顯示到頁面上。就像我們的書本,這不過這裏的動態,可能因爲查詢條件的不同,頁面的內容就不同,所以靈活應用,弄清楚查詢條件,編寫好分頁查詢語句,那麼什麼問題都解決了。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章