处理分页问题
分页问题总分为物理分页和逻辑分页两大类。物理(SQL)分页又有pagehelper分页插件、lambda函数分页最为普遍;逻辑分页很少使用,因为当处理数据超过10万条以后可能会超载。
**老铁们点个赞吧,给小白点鼓励!**
前言
每次pagehelper分页出问题,遇到苦笔的分页问题都去百度,全都是pagehelper分页的不同工具类的使用,最后解决问题的办法还是依赖强大的SQL函数。
提示:以下是逻辑分页和物理分页的总括图
一、物理分页
物理分页依赖的是某一物理实体,这个物理实体就是数据库,比如MySQL数据库提供了limit关键字,程序员只需要编写带有limit关键字的SQL语句,数据库返回的就是分页结果。
1.pagehelper分页
- spring是三层架构,controller层是接收前端的持久层,分页也一般是在这一层处理。
- pagehelper仅仅是对从servise层中的第一条查询SQL返回的数据进行分页。
- servise层不能改变从DAO层获取的List长度,只能改变list中的元素
导入maven的pagehelper插件为
强烈推荐阅读——浅析pagehelper分页原理
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>4.1.6</version>
</dependency>
controller层pagehelper应用的代码为
int pageNum;
int pageSize;
if (map.get("pageNum") == null || map.get("pageNum") == "") {
pageNum = 1;
} else {
pageNum = Integer.parseInt(map.get("pageNum").toString());
}
if (map.get("pageSize") == null || map.get("pageSize") == "") {
pageSize = 10;
} else {
pageSize = Integer.parseInt(map.get("pageSize").toString());
}
PageHelper.startPage(pageNum, pageSize);
List<PageData> appUserList = memberConsoleService.appUserList(map);
PageInfo<PageData> page = new PageInfo<PageData>(appUserList, pageSize);
return R.ok().put("list", appUserList).put("count", page.getTotal());
2.lambda函数分页
lambda函数是java8才有的新特性,lambda函数与pagehelper分页都是SQL分页。
- lambda函数仅仅是对从servise层中的最后一条查询SQL返回的数据进行分页。
- servise层不能改变从DAO层获取的List长度,只能改变list中的元素
- 这两种方法都有很明显的缺点,缺没有办法,害
lambda函数在controller层的应用为
int pageIndex;
int pageSize;
if (map.get("pageSize") != null && map.get("pageNum") != null && !"".equals(map.get("pageSize"))
&& !"".equals(map.get("pageNum"))) {
pageIndex = Integer.parseInt(map.get("pageNum").toString());// 当前页 前端传
pageSize = Integer.parseInt(map.get("pageSize").toString());// 每页显示条数 前端传
} else {
pageIndex = 1;// 当前页 前端传
pageSize = 10;// 每页显示条数 前端传
}
List<Map<String, Object>> List = firstAccountservice.querySystemAnnouncementList(map);
int total = (int) List.stream().filter(s -> !s.isEmpty()).count();// 总条数
List<Map<String, Object>> collect = List.stream().skip(pageSize * (pageIndex - 1)).limit(pageSize)
.collect(Collectors.toList());// 数据
return R.ok().put("list", collect).put("count", total);
3.MySQL中limit函数
limit是MySQL内置函数,其作用是用于限制du查询结果的条数。
- 查询的语法:SELECT * FROM table LIMIT [offset,] rows | rows OFFSET offset
- select * from table limit 5; --返回前5行
- select * from table limit 0,5; --同上,返回前5行
- select * from table limit 5,10; --返回6-15行
现在查到的limit函数的应用以及详解都差不多,也不知道谁抄谁的,我就推荐一个你们可以去看看(主要是我也没怎么用)
mysql分页——Mysql中limit的语法
二、逻辑分页
逻辑分页依赖的是程序员编写的代码。数据库返回的不是分页结果,而是全部数据,然后再由程序员通过代码获取分页数据,常用的操作是一次性从数据库中查询出全部数据并存储到List集合中,因为List集合有序,再根据索引获取指定范围的数据。
1.逻辑分页详解
- 逻辑分页显示从servise层获取的全部数据放到内存中,然后在controller层进行分页。
- 相对于物理分页,逻辑分页的工具包更多,我这里有一个搜到的工具包,分享给你们看看
逻辑分页的工具包:
package com.intelsrc.bean;
import java.util.List;
@SuppressWarnings("unchecked")
public class PageBean {
private List list ;
private int allRow;
private int totalPage;
public int getTotalPage() {
return totalPage;
}
public void setTotalPage(int totalPage) {
this.totalPage = totalPage;
}
private int currentPage;
private int pageSize;
private boolean isFirstPage;
private boolean isLastPage;
private boolean hasNextPage;
private boolean hasPreviousPage;
@SuppressWarnings("unchecked")
public List getList() {
return list;
}
@SuppressWarnings("unchecked")
public void setList(List list) {
this.list = list;
}
public int getAllRow() {
return allRow;
}
public void setAllRow(int allRow) {
this.allRow = allRow;
}
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;
}
public void init(){
this.isFirstPage=this.isFirstPage();
this.isLastPage=this.isLastPage();
this.hasNextPage=this.isHasNextPage();
this.hasPreviousPage=this.isHasPreviousPage();
}
public boolean isFirstPage() {
return currentPage==1;
}
public boolean isLastPage() {
return currentPage==totalPage;
}
public boolean isHasNextPage() {
return currentPage!=1;
}
public boolean isHasPreviousPage() {
return currentPage!=totalPage;
}
/**
* 计算总页数,静态方法,供外部直接通过类名调用
* @param pageSize
* @param allRow
* @return 总页数
*/
public static int countToltalPage(final int pageSize,int allRow){
int toltalPage=allRow%pageSize==0?allRow/pageSize:allRow/pageSize+1;
return toltalPage;
}
/**
* 计算当前页开始记录
* @param pageSize
* @param currentPage
* @return 当前页开始记录号
*/
public static int countOffset(final int pageSize,final int currentPage){
final int offset=pageSize*(pageSize-1);
return offset;
}
/**
* 计算当前页,若为0或者请求的URL中没有"?page=",则用1代替。
* @param page page 传入的参数(可能为空,即0,则返回1)
* @return 当前页
*/
public static int countCurrentPage(int page){
final int curPage = (page==0?1:page);
return curPage;
}
}
总结:两种分页的区别
分页的引用:物理和逻辑分页
物理分页相比于逻辑分页不会造成内存溢出,但翻页的数据相比于逻辑分页又慢,所以根据实际情况选择分页方式,如果数据量不大,可以考虑使用逻辑分页使翻页速度加快。。