数据分页
必须的的参数
总数据条数(count)
- 来源:从数据库中查询获得
每页展示多少条数据(pageSize)
- 来源:前端获取
当前所在的页码(currentPage)
- 来源:前端获取
总页数(countPage)
- 来源:计算得来
总页数 = 总数据条数 / 每页展示条数
countPage = count / pageSize
数据本身
- 来源:数据库查询
物理分页
什么是物理分页
所谓的物理分页其实就是直接通过数据库来实现返回一部分数据。每次只从数据库中查询一页的数据。与之相对应的还有逻辑分页。
Mysql中的实现语句
SELECT * FROM `shop` LIMIT (currentPage-1)*pageSize, pageSize;
Java程序
private void doPhysicalPaganation(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 获取页面传递过来的参数
String sCurrentPage = req.getParameter("currentPage");
String sPageSize= req.getParameter("pageSize");
// 当前页码默认展示第一页
int currentPage = 1;
try {
// 如果前端传递了具体的页码,我们就用前端传过来的
currentPage = Integer.parseInt(sCurrentPage);
} catch (NumberFormatException e) {
}
int pageSize = 10;
try {
// 如果前端传递了具体的页码,我们就用前端传过来的
pageSize = Integer.parseInt(sPageSize);
} catch (NumberFormatException e) {
}
Paganation<Student> paganation = new Paganation<>();
paganation.setCurrentPage(currentPage);
paganation.setPageSize(pageSize);
// 分页查询
studentDao.findByPageWithPhysical(paganation);
req.setAttribute("page", paganation);
req.getRequestDispatcher("physical.jsp").forward(req, resp);
}
public Paganation<Student> findByPageWithPhysical(Paganation<Student> pageParam) {
Paganation<Student> page = pageParam;
Connection conn = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
// 获取连接
conn = JDBCTools.getConnection();
// 获取当前页要展示的数据
// 创建预编译对象,预编译SQL语句
pstmt = conn.prepareStatement("select * from student limit ?,?");
// limit关键字第一个参数表示跳过结果集中的多少条数据
pstmt.setInt(1, (pageParam.getCurrentPage() - 1) * pageParam.getPageSize());
// limit关键字第二个参数表示从结果集中取多少条数据
pstmt.setInt(2, pageParam.getPageSize());
// 执行语句,获取结果集
rs = pstmt.executeQuery();
// 封装结果集
List<Student> datas = new ArrayList<Student>();
while(rs.next()) {
Student student = new Student();
student.setStuId(rs.getString("stu_id"));
student.setStuName(rs.getString("stu_name"));
student.setSex(rs.getString("sex"));
student.setAge(rs.getInt("age"));
student.setScience(rs.getString("science"));
student.setTelephone(rs.getString("telephone"));
datas.add(student);
}
// 将获取到的当前页要展示的数据封装到page对象中
page.setData(datas);
// 查询总数据条数
pstmt = conn.prepareStatement("select count(*) from student");
rs = pstmt.executeQuery();
int totalCount = 0;
if(rs.next()) {
totalCount = rs.getInt(1);
}
page.setTotalCount(totalCount);
} catch (SQLException e) {
e.printStackTrace();
}
return page;
}
逻辑分页
什么是逻辑分页
所谓的逻辑分页其实就是通过内存来进行分页。具体来说,首次查询数据时,将所有数据都取出放到内存中,展示其他页的数据时,在内存中实现数据的截取,展示。
Mysql中的实现语句
SELECT * FROM `shop` ;
Java程序
private void doLogicPaganation(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 获取页面传递过来的参数
String sCurrentPage = req.getParameter("currentPage");
String sPageSize= req.getParameter("pageSize");
// 当前页码默认展示第一页
int currentPage = 1;
try {
// 如果前端传递了具体的页码,我们就用前端传过来的
currentPage = Integer.parseInt(sCurrentPage);
} catch (NumberFormatException e) {
}
int pageSize = 10;
try {
// 如果前端传递了具体的页码,我们就用前端传过来的
pageSize = Integer.parseInt(sPageSize);
} catch (NumberFormatException e) {
}
Paganation<Student> paganation = new Paganation<>();
paganation.setCurrentPage(currentPage);
paganation.setPageSize(pageSize);
// 分页查询
studentDao.findByPageWithLogic(paganation);
req.setAttribute("page", paganation);
req.getRequestDispatcher("logic.jsp").forward(req, resp);
}
List<Student> cache = new ArrayList<>();
public Paganation<Student> findByPageWithLogic(Paganation<Student> pageParam) {
Paganation<Student> page = pageParam;
Connection conn = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
List<Student> datas = null;
// 当缓存中有数据时,直接从缓存中取当前页数据,无需查数据库
if(cache.size() > 0) {
datas = getPageData(page);
} else {
// 如果缓存中没有数据,从数据库中查询所有数据,放入缓存中
// 获取连接
conn = JDBCTools.getConnection();
// 获取当前页要展示的数据
// 创建预编译对象,预编译SQL语句
pstmt = conn.prepareStatement("select * from student");
// 执行语句,获取结果集
rs = pstmt.executeQuery();
// 封装结果集
cache.clear();
while(rs.next()) {
Student student = new Student();
student.setStuId(rs.getString("stu_id"));
student.setStuName(rs.getString("stu_name"));
student.setSex(rs.getString("sex"));
student.setAge(rs.getInt("age"));
student.setScience(rs.getString("science"));
student.setTelephone(rs.getString("telephone"));
cache.add(student);
}
// 将获取到的当前页要展示的数据封装到page对象中
datas = getPageData(page);
}
page.setData(datas);
page.setTotalCount(cache.size());
} catch (SQLException e) {
e.printStackTrace();
}
return page;
}
/**
* 从缓存中获取当前页要展示的数据
* @param page
* @return
*/
private List<Student> getPageData(Paganation<Student> page) {
List<Student> datas = new ArrayList<>();
int startIdx = (page.getCurrentPage() - 1)*page.getPageSize();
int endIdx = page.getCurrentPage() * page.getPageSize();
if(endIdx > cache.size()) {
endIdx = cache.size();
}
datas = cache.subList(startIdx, endIdx);
return datas;
}
两种分页的优缺点
- 逻辑分页效率高,占用内存空间,适合查询的数据少但是查询次数多的情况。
- 物理分页效率低,节省内存空间,适合查询次数少但是查询数据较大的情况。