Java中的分页查询

   原文章:点击打开链接

   分页查询,就是将将过多的结果在有限的界面上分好多页来显示,这个是很多网站常用的功能,也是最基本的功能,今天简单总结一下。


          分页以前听人们说都是一项技术,但是我觉的不尽然。我认为分页是将数据库的数据,利用一些特殊的sql语句来进行查询,显示理所应当显示的内容,更恰当的说可以是对SQL语句的灵活运用,对逻辑思维的简单使用。


         一,一般人们将分页查询分为两类:逻辑分页,物理分页,我们先从理论上理解一下:

             1,逻辑分页概述:就是用户第一次访问时,将数据库的所有记录全部查询出来,添加到一个大的集合中,然后存放在session对象,然后通过页码计算出当前页需要显示的数据内容,存储到一个小的list的集合中,并将之存储到request对象中,跳转到JSP页面,进行遍历显示。 当用户第二次访问时,只要不关闭浏览器,我们还会从session中获取数据,来进行显示。为什么叫逻辑分页呢?因为此种方法是在内存的session对象中进行计算分页显示的,而不是真正的将我们数据库进行分页的。

        来看它的一些缺点吧:

              a,如果需要查询的数据量过大,session将耗费大量的内存;

              b,因为是在session中获取数据,如果第二次或者更多此的不关闭浏览器访问,会直接访问session,从而不能保证数据是最新的。

        小结:这种分页很少使用。但是在数据量小,不会被修改的数据,使用逻辑分页会提高程序的执行效率。

 

           2,物理分页概述:使用数据库自身所带的分页机制,例如,Oracle数据库的rownum,或者Mysql数据库中的limit等机制来完成分页操作。因为是对数据库实实在在的数据进行分页条件查询,所以叫物理分页。每一次物理分页都会去连接数据库。

            优点:数据能够保证最新,由于根据分页条件会查询出少量的数据,所以不会占用太多的内存。

            缺点:物理分页使用了数据库自身带的机制,所以这样的SQL语句不通用,导致不能进行数据库的移植。

           小结:在实际中物理分页还是使用的较多的。

 


  二,看一下逻辑分页查询的应用:


  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中一个是在数据库中,这里物理分页总结一下多条件查询分页显示的过程,这里也将分页对象进行封装了:

            先看一下分页对象的编写:

  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>  

 有了这个分页对象,我就可以利用它了,看我们动态参数分页查询的过程,重点看注释步骤:

  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>  



          分页查询将数据量分成几批显示到页面上。就像我们的书本,这不过这里的动态,可能因为查询条件的不同,页面的内容就不同,所以灵活应用,弄清楚查询条件,编写好分页查询语句,那么什么问题都解决了。
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值