前言
在使用数据库的过程中,不可避免的需要使用到分页的功能,可是JDBC的规范对此却没有很好的解决。对于这个需求很多朋友都有自己的解决方案,比如使用Vector等集合类先保存取出的数据再分页。但这种方法的可用性很差,与JDBC本身的接口完全不同,对不同类型的字段的支持也不好。这里提供了一种与JDBC兼容性非常好的方案。
JDBC和分页
Sun的JDBC规范的制定,有时很让人哭笑不得,在JDBC1.0中,对于一个结果集(ResultSet)你甚至只能执行next()操作,而无法让其向后滚动,这就直接导致在只执行一次SQL查询的情况下无法获得结果集的大小。所以,如果你使用的是JDBC1.0的驱动,那么是几乎无法实现分页的。
好在Sun的JDBC2规范中很好的弥补了这一个不足,增加了结果集的前后滚动操作,虽然仍然不能直接支持分页,但我们已经可以在这个基础上写出自己的可支持分页的ResultSet 了。
和具体数据库相关的实现方法
有一些数据库,如Mysql, Oracle等有自己的分页方法,比如Mysql可以使用limit子句,Oracle可以使用ROWNUM来限制结果集的大小和起始位置。这里以Mysql为例,其典型代码如下:
// 计算总的记录条数
String SQL = "SELECT Count(*) AS total " + this.QueryPart;
rs = db.executeQuery(SQL);
if (rs.next())
Total = rs.getInt(1);
// 设置当前页数和总页数
TPages = (int)Math.ceil((double)this.Total/this.MaxLine);
CPages = (int)Math.floor((double)Offset/this.MaxLine+1);
// 根据条件判断,取出所需记录
if (Total > 0) {
SQL = Query + " LIMIT " + Offset + " , " + MaxLine;
rs = db.executeQuery(SQL);
}
return rs;
}
毫无疑问,这段代码在数据库是Mysql时将会是漂亮的,但是作为一个通用的类(事实
上我后面要提供的就是一个通用类库中的一部分),需要适应不同的数据库,而基于这个类(库)的应用,也可能使用不同的数据库,所以,我们将不使用这种方法。
另一种繁琐的实现方法
我看过一些人的做法(事实上包括我在内,一开始也是使用这种方法的),即不使用任何封装,在需要分页的地方,直接操作ResultSet滚到相应的位置,再读取相应数量的记录。其典型代码如下:
<%
sqlStmt = sqlCon.createStatement(,
;
strSQL = "select name,age from test";
//执行SQL语句并获取结果集
sqlRst = sqlStmt.executeQuery(strSQL);
//获取记录总数
https://www.doczj.com/doc/e28481293.html,st();
intRowCount = sqlRst.getRow();
//记算总页数
intPageCount = (intRowCount+intPageSize-1) / intPageSize;
//调整待显示的页码
if(intPage>intPageCount) intPage = intPageCount;
%>
姓名 | 年龄 |
---|---|
<%=sqlRst.getString(1)%> | <%=sqlRst.getString(2)%> |
很显然,这种方法没有考虑到代码重用的问题,不仅代码数量巨大,而且在代码需要修改的情况下,将会无所适从。
使用Vector进行分页
还见过另一些实现分页的类,是先将所有记录都select出来,然后将ResultSet中的数据都get出来,存入Vector等集合类中,再根据所需分页的大小,页数,定位到相应的位置,读取数据。或者先使用前面提到的两种分页方法,取得所需的页面之后,再存入Vector中。
扔开代码的效率不说,单是从程序结构和使用的方便性上讲,就是很糟糕的。比如,这种做法支持的字段类型有限,int, double, String类型还比较好处理,如果碰到Blob, Text等类型,实现起来就很麻烦了。这是一种更不可取的方案。
一个新的Pageable接口及其实现
很显然,看过上面三种实现方法后,我们对新的分页机制有了一个目标,即:不与具体数据库相关;尽可能做到代码重用;尽可能与原JDBC接口的使用方法保持一致;尽可能高的效率。
首先,我们需要提供一个与,把它命名为Pageable,接口定义如下:
public interface Pageable extends
/**返回总页数
*/
int getPageCount();
/**返回当前页的记录条数
*/
int getPageRowsCount();
/**返回分页大小
为什么需要分页? 1.从客户角度来讲,数据内容过多,查看数据非常不便。 2.从服务器和网络的角度来讲,查这么多数据,传输这么多数据,是一种效率很低的做法。分页的核心SQL: 最简单最原始的分页: 分页的简单过程: 用户点击第一页传递一个参数:Num=1到后台,服务器获取num=1将该参数传到Dao 中,dao中:select * from tb_article where id>10 limit ?,?;, ps.setint((num-1)*10),返回一个List,传递到jsp中进行显示,发送给客户端。 1.
2.
3.访问:channel.jsp,然后点击在下面的页号导航即可看到简单的分页效果。 首页上一页1,2,3,4,5,6,7,8,9,10 下一页末页共101页 分页的实现原理: 1.获得需要显示的总的记录数rowCount—》从数据库中取 2.设定每页最多显示的记录数size—》10 3.指定显示的页码:num →作为参数得到 4.所要显示的数据对象→根据startRow和size从数据库中查出! 5.根据rowCount,size,num可计算出其余的元素: a)本页面从第几个记录开始:startRow = (this.num-1) * size; b)共有多少页:pageCount = (int) Math.ceil((double)rowCount/size); c)list:包含了所要显示的数据对象的集合 d)下一页:next=Math.min( this.pageCount, this.num+1) e)上一页:prev = Math.max(1 , this.num-1) f)页号控制元素: numCount:每页最多显示多少页号。(一共显示numCount+1个页号) start = Math.max(this.num-numCount/2, first); //本页显示页号从多少页开始 end = Math.min(start+numCount, last); //本页显示页号在多少页结束 页号控制: if(end-start < numCount){ //当本页总显示的页号数不够numCount时,如何计算起始页号。 start = Math.max(end-numCount, 1); } 分页实现步骤 Pagenation工具类代码:
分页的实现原理: 1.获得需要显示的总的记录数rowCount—》从数据库中取 2.设定每页最多显示的记录数size—》10 3.指定显示的页码:num 作为参数得到 4.根据rowCount,size,num可计算出其余的元素: a)本页面从多少行记录开始:startRow = (this.num-1) * size ; b)共有多少页:pageCount = (int) Math.ceil((double)rowCount/size); c)下一页:next=Math.min( this.pageCount, this.num+1) d)上一页:prev = Math.max(1 , this.num-1) e)页号控制元素: numCount:每页最多显示多少页号。(一共显示numCount+1个页号) start = Math.max(this.num-numCount/2, first); //本页显示页号从多少页开始 end = Math.min(start+numCount, last); //本页显示页号在多少页结束 页号控制: if(end-start < numCount){ //当本页总显示的页号数不够numCount时,如何计算起始页号。 start = Math.max(end-numCount, 1); } 分页实现步骤: 1.将Page类引入。需要自己修改的可自行修改。 package com.puckasoft.video.util; public class Page { private int num; //当前页号, 采用自然数计数 1,2,3,... private int size; //页面大小:一个页面显示多少个数据 private int rowCount;//数据总数:一共有多少个数据 private int pageCount; // 页面总数 private int startRow;//当前页面开始行, 第一行是0行 private int first = 1;//第一页页号 private int last;//最后页页号 private int next;//下一页页号 private int prev;//前页页号 private int start;//页号式导航, 起始页号 private int end;//页号式导航, 结束页号 private int numCount = 10;//页号式导航, 最多显示页号数量为numCount+1;这里显示11页。 public Page(int size, String str_num, int rowCount) { int num = 1; if (str_num != null) { num = Integer.parseInt(str_num);
java web 分页技术详解及代码 关于在java web上实现分页技术,方式实际上有很多,也各有个的特点,此处我只写些我的认识。java web分页无外乎两种,一种是直接取出来,放到一个集合里,通过传begin 和end 参数控制分页,还有一种就是把分页工作交给数据库,让数据库读取需要的begin~end 之间的数据。 我们这里,先看从数据库中读取的情况 操作数据库就需要tsql语句,mssqlserver2005新推出了一个row_number()很好用,还有就是mysql的limit也非常好使。 mssqlserver2005的如下: select * from (select row_number() over (order by ename) as rn, f.* from emp f) b where b.rn between 6 and 10; mysql的: select * from emp limit 5,5 mysql的应注意,使用limit时,表中必须用主键,还有limit后的两个参数分别代表(标识位,长度),标识位从0开始 现在开始一步步完成,首先完成model模块,建立pagebean import java.util.*; public class PageBean { private Collection objs;//从数据库中读的集合 private int totalCount;//总的条数 private int pageNo;//当前的页数 private int pageCount;//每页的条数 public int getPageCount() { return pageCount; } public void setPageCount(int pageCount) { this.pageCount = pageCount; }
《JSP web开发技术》课程教学大纲 课程名称:JSP web开发技术课程编码: 学时:54 学分:3 开课学期:5 课程类别:专业平台课 课程性质:选修 适用专业:计算机科学与技术(卓越计划) 先修课程:java程序设计基础 教学方式:课堂讲授为主,穿插课堂练习 教学手段:以多媒体教学手段为主,主要采用PPT、现场编程的方式,辅助手写板书
一、课程的性质、目的与任务 本课程是在学生修完Java程序设计等相关课程后,使学生进一步掌握一种动态网页设计技术(JSP技术)。 通过本课程的学习,使学生掌握JSP技术的基础知识,以及动态网页设计的基本思想方法,会应用JSP进行基本的程序设计。 二、教学内容及基本要求 单元1JSP简介 1. 教学目的和要求: 通过本单元的学习,使学生了解编写简单的html网页,利用Tomcat建立一个网站,在JSP中得到用户输入的值。 2. 知识点: (1)编写简单的html页面和安装Tomcat 补充编写一个简单、无标签的html页面,补充Tomcat安装、运行。 (2)配置Tomcat,建立一个简单的网站 设置web服务目录,补充配置Tomcat。 (3)使用MyEclipse开发网站 补充MyEclipse安装、配置Tomcat和JRE,补充在MyEclipse中新建Web网站。 (4)html标签 补充form、input、text、submit、password,request对象,补充textarea、radio、checkbox,用JSP如何得到选择的多个值,补充select标签。 3. 建议课时: 7课时。 4. 教学重点和难点: html页面各种标签,学会安装和配置Tomcat,在JSP中得到用户输入的值。 5. 复习与作业要求: 着重复习html页面各种标签,学会安装和配置Tomcat,在JSP中得到用户输入的值。 安装Tomcat,并完成一个简单的网站。 6. 考核知识点: 在Tomcat下建立网站、利用html标签输入值,在JSP中得到。 7. 辅助教学活动: 上机实践 单元2 JSP内置对象 1. 教学目的和要求: 通过本单元的学习,使学生了解JSP内部对象的基本概念,主要掌握out、request、response、session对象的功能以及使用方法。能够利用内部对象实现与客户端的交互。 2.知识点:
<%@ page contentType="text/html; charset=gb2312" %> <%@ page language="java" import="java.sql.*" %> /** * 华夏课程设计西西~~ */
目前比较广泛使用的分页方法是将查询结果缓存在HttpSession或有状态bean 中,翻页的时候从缓存中取出一页的数据进行显示。这种方法有两个主要的缺点:一是用户可能看到的是过期数据;二是如果数据量非常大时第一次查询遍历结果集会耗费很长时间,并且缓存的数据也会占用大量内存,效率明显下降[i]。其它常见的方法还有每次翻页都查询一次数据库,从ResultSet中只取出一页的数据(使用https://www.doczj.com/doc/e28481293.html,st();rs.getRow()获得总计录条数,使用rs.absolute()定位到本页起始记录)。这种方式在某些数据库(如oracle)的JDBC实现中差不多也是需要遍历所有记录,实验证明在记录数很大时速度非常慢[ii]。因此,本系统选用一种利用数据库分页的方法,即每次翻页的时候只从数据库里检索页面大小的块区的数据。这样虽然每次翻页都需要查询数据库,但查询出的记录数很少,网络传输数据量不大,会大大提升查询数据库的效率[iii]。 下面以查询定检记录模块的分页技术为例,详细讲述本系统分页技术实现的具体过程。在查询定检记录的CraftCheckServlet中定义各个变量与分页算法,分页算法为:在数据库中查询得到的总记录数totalnum对每页显示记录数pagesize 取余,如果整除则分页的总页数totalpage = totalnum/pagesize,如果没有整除则totalpage = totalnum/pagesize+1,具体代码如下。在对数据库进行查询的CraftCheckDao中,利用数据库分页查询的技术编写的SQL语句如下所示。最后在CraftCheck.jsp中做好分页的显示,具体的代码如下所示。 1、Servlet中的代码部分 package craft.controller; public class CraftCheckServlet extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { request.setCharacterEncoding("UTF-8"); response.setContentType("text/html;charset=utf-8"); PrintWriter pr = response.getWriter(); String currentpageno = request.getParameter("currentpageno");//定义当前页码 String pagesizeno = request.getParameter("pagesize");//定义每页数据大小 int startpage= 1;//起始页 int totalpage=4;//总页数 int pagesize =3;//每页显示数据
JSP实现分页功能 分页须知知识点: (1)JDBC2.0的可滚动结果集。 (2)HTTP GET请求。 一、可滚动结果集 Connection con = DriverManager.getConnection(); PreparedStatement stmt = con.prepareStatement(sql,ResultSet.TYPE_FORWARD_ONLY,ResultSet.CONCUR_RE AD_ONLY); ResultSet rs = stmt.executeQuery(); 常用方法: (1)rs.absolute(n); 可以将指针跳到第n行。 (2)rs.relative(n); 可以将指针相对向下或向上n行。 (3)rs.first(); (4)https://www.doczj.com/doc/e28481293.html,st(); (5)int curRow = rs.getRow(); 指针指向的当前行 二、功能实现分解 1.计算结果的个数 https://www.doczj.com/doc/e28481293.html,st(); int size = rs.getRow(); 即可得到结果的个数。 2.得到需要分几页 如果一页能够放5条记录,则 int pageCount = (size%5==0)?(size/5):(size/5+1); 即可获得需要分几页。
3.控制一页中规定显示记录个数 如果一页能显示5条记录,可以通过使用count进行计数。 int count = 0; do{ if(count>=5) break; ..... count++; }while(rs.next()); 通过break语句,能够使其显示到超过规定条目就跳出。 4.如何知道当前是第几页 通过HTTP get的特点,在地址栏中标明当前地址,如http://.......?curPage=1表示现在是第一页。 String tmp = request.getParameter("curPage"); if(tmp==null){ tmp="1"; } curPage = Integer.parseInt(tmp); 可以获得当前页。 注意: rs.absolute(1);表示指向第一条记录; 不存在rs.absolute(0); rs.absolute((curPage-1)*PAGESIZE+1); 把结果集指针调整到当前页应该显示的记录的开始. 比如如果一页显示5条记录,当前页是第二页,则需要把指针调整到6,当前页是第三页,则需要把指针调整为11. 5.点击首页、上一页、下一页、尾页的行为 下一页
JavaBean+Servlet+jsp实现分页显示(原创)实现效果图 代码: (1)JavaBean PageDivide.java package com.bean; import java.io.UnsupportedEncodingException; import java.sql.*; import java.util.ArrayList; import java.util.List; import com.myutil.DBCon; public class PageDivide { int sumRecord=0; //显示的总记录条数 int pageRecord=5; //每页显示的记录数 int pageNum=0; //显示的总页码数
int showPage=1; //所要显示的页码数 private Connection con=null; private PreparedStatement pstm=null; private ResultSet rs=null; private String sql="select * from category"; public PageDivide(){ //数据库连接 con=DBCon.getConn(); try { pstm=con.prepareStatement(sql,ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CON CUR_UPDATABLE); rs=pstm.executeQuery(); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } this.sumRecord=this.getSumRecord(); // this.setSumRecord(this.getSumRecord()); this.pageNum=this.getPageNum(); } //获取总记录数 public int getSumRecord() { try { rs=pstm.executeQuery(); https://www.doczj.com/doc/e28481293.html,st(); sumRecord=rs.getRow(); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } return sumRecord; } public List getData(int n){ List list=new ArrayList(); if(n<1) {
一利用jsp实现Oracle数据库中表格的分页浏览:
二在Oracle数据库中建立表格,包含员工的工号、姓名、性别、工龄、工资等字段,并实现增删改查操作。 (1)所建的worker表格如下: (2)Input.jsp运行结果如下:
(3)Inputcheck.jsp运行结果如下:
Pagebreak.jsp代码如下: <%@page contentType="text/html"pageEncoding="UTF-8" import="java.sql.*"%>
工号 | 姓名 | 性别 | 工龄 | 工资 |
---|