一.MySQL分页基础
1.1.SQL语句
- 分页MySQL语句是:
SELECT * FROM student LIMIT 0,10;
- 是从0开始
- 解释: LIMIT 第几个数据,要查多少条数据
- 即从第0条开始,到第9条数据
1.2.逻辑
- 要实现分页,必须知道某一页的数据从哪里开始,到哪里结束。
- 规定:页面大小:每页显示的数据量。(假设每页显示10条数据)
- 从第0页开始计数
- 第n页的数据: 第(n-1) * 10+1条 – 第n * 10条
第几页 | 开始数据行 | 结束数据行 |
---|---|---|
0 | 0 | 9 |
1 | 10 | 19 |
2 | 20 | 29 |
n | n*10 | (n+1)*10-1 |
- MYSQL实现分页的sql:
limit 开始,多少条
第0页
select * from student limit 0,10 ;
第1页
select * from student limit 10,10 ;
第2页
select * from student limit 20,10 ;
第n页
select * from student limit n*10,10
mysql的分页语句:
select * from student limit 页数*页面大小,页面大小
1.4.oracle,sqlserver分页(引用)
b.oracle分页:
sqlserver/oracle:从1开始计数
第n页 开始 结束
1 1 10
2 11 20
3 21 30
n (n-1)*10+1 n*10
select *from student where sno >=(n-1)*10+1 and sno <=n*10 ; --此种写法的前提:必须是Id连续 ,否则 无法满足每页显示10条数据
select rownum,t.*from student t where rownum >=(n-1)*10+1 and rownum <=n*10 order by sno;
--1.如果根据sno排序则rownum会混乱(解决方案:分开使用->先只排序,再只查询rownum) 2.rownum不能查询>的数据
select s.* from student s order by sno asc;
select rownum, t.* from
(select s.* from student s order by sno asc) t
where rownum >=(n-1)*10+1 and rownum <=n*10 ; ;
//ORACLE\sqlserver都是从1开始计数: (n-1)*10+1 --- n*10
oracle的分页查询语句:
select *from
(
select rownum r, t.* from
(select s.* from student s order by sno asc) t 10000
)
where r>=(n-1)*10+1 and <=n*10 ; 10
优化:
select *from
(
select rownum r, t.* from
(select s.* from student s order by sno asc) t
where rownum<=n*10
)
where r>=(n-1)*10+1 ;
select *from
(
select rownum r, t.* from
(select s.* from student s order by sno asc) t
where rownum<=页数*页面大小
)
where r>=(页数-1)*页面大小+1 ;
SQLServer分页: 3种分页sql
row_number() over(字段) ;
sqlserver2003:top --此种分页SQL存在弊端(如果id值不连续,则不能保证每页数据量相等)
select top 页面大小 * from student where id not in
( select top (页数-1)*页面大小 id from student order by sno asc )
sqlserver2005之后支持:
select *from
(
select row_number() over (sno order by sno asc) as r,* from student
where r<=n*10
)
where r>=(n-1)*10+1 and ;
SQLServer此种分页sql与oralce分页sql的区别: 1.rownum ,row_number() 2.oracle需要排序(为了排序,单独写了一个子查询),但是在sqlserver 中可以省略该排序的子查询 因为sqlserver中可以通过over直接排序
sqlserver2012之后支持:
offset fetch next only
select * from student oreder by sno
offset (页数-1)*页面大小+1 rows fetch next 页面大小 rows only ;
(n-1)*10+1 --- n*10
mysql从0开始计数,Oracle/sqlserver 从1开始计数
二.SQL到Java联系(具体分页实现)
2.1 需要5个属性
2.2 数据总数(查数据库)
select count(*)..
2.3 页面大小(用户自定义)
每个页面显示的数据条数(20)
2.4 总页数(程序自动计算)
- 总页数 = 100/20 =数据总数/页面大小
- 总页数 = 103/20 = 数据总数/页面大小+1
- 总页数 = 数据总数%页面大小 == 0? 数据总数/页面大小 : 数据总数/页面大小+1;
2.5 当前页(页码)
2.6 当前页的对象集合 (查数据库,分页sql)
- 每页所显示的所有数据 (10个人信息)
List<Student>
三.项目构造(基于上一个项目的框架完善)
3.1 给DBUtil工具类增加查询总数方法
// 查询总数
public static int getTotalCint(String sql) {
int count = -1;
try {
pstmt = createPreparedStatement(sql, null);
rs = pstmt.executeQuery();
if (rs.next()) {
count = rs.getInt(1);
}
return count;
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}catch (Exception e) {
e.printStackTrace();
}finally {
closeAll(rs, pstmt, connection);
return count;
}
}
3.2 给dao层,service层添加方法(并在对应实现类具体实现)
3.2.1查询总数据数方法
3.2.2 查询每一页学生方法
3.2.3 具体代码(只有新增代码,前面有所属包)
package org.student.dao;
import org.student.entity.Student;
public interface IStudentDao {
// 查询总数据数
public int getTotalCount();
// 查询每一页所有学生
// currentPage:当前页 pageSize:页面大小
public List<Student> queryStudentsByPage(int currentPage,int pageSize);
package org.student.dao.impl;
// 查询总数据量
@Override
public int getTotalCount() {
String sql = "select count(*) from student";
return DBUtil.getTotalCint(sql);
}
// 返回每一次页面的数据集合
@Override // currentPage:当前页 pageSize:页面大小
public List<Student> queryStudentsByPage(int currentPage, int pageSize) {
String sql = "SELECT * FROM student LIMIT ?,?";
Object[] params = {currentPage*pageSize,pageSize};
ResultSet rs = DBUtil.executeQuery(sql, params);
List<Student> students = new ArrayList<Student>();
try {
while (rs.next()) {
int no = rs.getInt("sno");
String name = rs.getString("sname");
int age = rs.getInt("sage");
String address = rs.getString("saddress");
Student student = new Student(no, name, age,address);
students.add(student);
}
return students;
} catch (SQLException e) {
e.printStackTrace();
}catch (Exception e) {
e.printStackTrace();
}finally {
DBUtil.closeAll(DBUtil.rs, DBUtil.pstmt,DBUtil.connection );
}
return students;
}
package org.student.service;
public interface IStudentService {
public List<Student> queryStudentsByPage(int currentPage ,int pageSize);
public int getTotalCount();
package org.student.service.impl;
// 业务逻辑层:逻辑性增删改查( 增:查+增),对dao层进行组装
public class StudentServiceImpl implements IStudentService{
IStudentDao studentDao = new StudentDaoImpl();
//查询当前页的数据集合
@Override
public List<Student> queryStudentsByPage(int currentPage, int pageSize) {
return studentDao.queryStudentsByPage(currentPage, pageSize);
}
//查询数据总条数
@Override
public int getTotalCount() {
return studentDao.getTotalCount();
}
3.3 分页的帮助类(Page)
- 因为分页的元素过多,所以建一个类来存放数据
- 这个类当做实现类,所以建在
entity
层 - 里面的元素就是之前的5个元素
- 因为总页数,不需要赋值,需自动计算,所以去掉setter方法
- 再有总数据数,页面大小后就可以计算总页数,所以将对其赋值放在setPageSize()里:
public void setPageSize(int pageSize) {
this.pageSize = pageSize;
// 自用计算总页数 = 数据总数%页面大小==0?数据总数/页面大小 : 数据总数/页面大小+1
this.totalPage = this.totalCount%this.pageSize == 0 ? this.totalCount/this.pageSize :this.totalCount%this.pageSize+1;
}
6.但是要注意赋值顺序,需要先赋总页数值,再赋页面大小值,也可以改进:
private void setTotalPage() {
// 自用计算总页数 = 数据总数%页面大小==0?数据总数/页面大小 : 数据总数/页面大小+1
// 排除页面大小为0,出现异常情况
if(this.pageSize != 0){
this.totalPage = this.totalCount%this.pageSize == 0 ? this.totalCount/this.pageSize :this.totalCount%this.pageSize+1;
}
}
public void setTotalCount(int totalCount) {
this.totalCount = totalCount;
this.setTotalPage();
}
public void setPageSize(int pageSize) {
this.pageSize = pageSize;
this.setTotalPage();
}
- 具体代码
package org.student.entity;
// 分页的帮助类
import java.util.List;
public class Page {
// 当前页
private int currentpage;
// 页面大小
private int pageSize;
// 总数据
private int totalCount;
// 总页数,不需要赋值,需自动计算,去掉setter方法
private int totalPage;
// 当前页的数据集合
private List<Student> students;
public Page() {
}
public Page(int currentpage, int pageSize, int totalCount, int totalPage, List<Student> students) {
super();
this.currentpage = currentpage;
this.pageSize = pageSize;
this.totalCount = totalCount;
this.totalPage = totalPage;
this.students = students;
}
public int getCurrentpage() {
return currentpage;
}
public void setCurrentpage(int currentpage) {
this.currentpage = currentpage;
}
public int getPageSize() {
return pageSize;
}
public void setPageSize(int pageSize) {
this.pageSize = pageSize;
// 自用计算总页数 = 数据总数%页面大小==0?数据总数/页面大小 : 数据总数/页面大小+1
this.totalPage = this.totalCount%this.pageSize == 0 ? this.totalCount/this.pageSize :this.totalCount%this.pageSize+1;
}
public int getTotalCount() {
return totalCount;
}
public void setTotalCount(int totalCount) {
this.totalCount = totalCount;
}
public int getTotalPage() {
return totalPage;
}
public List<Student> getStudents() {
return students;
}
public void setStudents(List<Student> students) {
this.students = students;
}
}
3.4 新建分页servlet(QueryStudentByPage.java)
3.4.1 给Page对象传值,放入request中
3.4.2 配置Web.xml(先获取值,再展示值)
<welcome-file>QueryStudentByPage</welcome-file>
package org.student.servlet;
public class QueryStudentByPage extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("utf-8");
IStudentService service = new StudentServiceImpl();
// 将分页所需的五个字段(实际只有一个,所以需要组装4个)
Page pages = new Page();
// 数据总数
int totalCount = service.getTotalCount();
// 1. pages赋值totalCount
pages.setTotalCount(totalCount);
// 第一次进入,获取的是第几页,从0页开始
String cPage = request.getParameter("currentPage");
if (cPage == null) {
cPage = "0";
}
int currentPage = Integer.parseInt(cPage);
// 2. pages赋值currentPage
pages.setCurrentpage(currentPage);
// 页面大小,先手动给定值
int pageSize = 5;
// 3. pages赋值pageSize,注意顺序
pages.setPageSize(pageSize);
// 获取动态集合
List<Student> students = service.queryStudentsByPage(currentPage, pageSize);
// 4. pages赋值 List<Student> students
pages.setStudents(students);
// 存入数据
request.setAttribute("pages", pages);
// 因为request中有数据,通过请求转发(重定向丢失request),跳转到index.jsp显示数据
request.getRequestDispatcher("index.jsp").forward(request, response);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doGet(request, response);
}
}
3.5 index.jsp(展示主要代码)
- 代码里思维是从0页开始
- 假设一共10页,则有0–9页,下来看代码
- 所以 当
pages.getCurrentpage() ==pages.getTotalPage()-1
是到达尾页 - 所以
pages.getCurrentpage() ==0
是跳转首页 - 所以
pages.getTotalPage()-1
是跳转尾页
<body>
<table border = "1px">
<tr>
<th>学号</th>
<th>姓名</th>
<th>年龄</th>
<th>操作</th>
</tr>
<%
// 从QueryStudentByPage 跳转过来的(在xml里改过了),
//需要先查询,再显示数据,因为这里要获取数据
// 获取request域里的数据,Object类型转换
Page pages = (Page) request.getAttribute("pages");
for(Student student : pages.getStudents() ){
%>
<tr>
<!-- 学号跳转查询此人信息 -->
<th><a href="QueryStudentBySnoServlet?sno=<%=student.getSno() %>"><%=student.getSno() %></a></th>
<th><%=student.getSname() %></th>
<th><%=student.getSage() %></th>
<th><a href="DeleteStudentServlet?sno=<%=student.getSno() %>">删除</a></th>
</tr>
<%
}
%>
</table>
<a href="add.jsp">新增</a>
<%
if(pages.getCurrentpage() ==pages.getTotalPage()-1){ //尾页
%>
<a href="QueryStudentByPage?currentPage=0">首页</a>
<a href="QueryStudentByPage?currentPage=<%=pages.getCurrentpage()-1%> ">上一页</a>
<%
}
else if(pages.getCurrentpage() ==0){//首页
%>
<a href="QueryStudentByPage?currentPage=<%=pages.getCurrentpage()+1%> ">下一页</a>
<a href="QueryStudentByPage?currentPage=<%=pages.getTotalPage()-1%>">尾页</a>
<%
}
else{//中间
%>
<a href="QueryStudentByPage?currentPage=0">首页</a>
<a href="QueryStudentByPage?currentPage=<%=pages.getCurrentpage()-1%> ">上一页</a>
<a href="QueryStudentByPage?currentPage=<%=pages.getCurrentpage()+1%> ">下一页</a>
<a href="QueryStudentByPage?currentPage=<%=pages.getTotalPage()-1%>">尾页</a>
<%
}
%>
<!-- 没有完善的手动输入一页有多少条数据 功能
<br/>
每页显示
<select>
<option value="3">3</option>
<option value="5">5</option>
<option value="10">10</option>
</select>
条
-->
</body>