怎么进行分页数据的查询,如何判断是否有下一页?
1.背景介绍
在开发过程当中,接触比较多的有MySQL、SQLServer、Oracle这三种数据库,这三种数据库都有自己内部的方法可以进行分页查询,MySQL用的是limit进行分页查询,SQLServer用的是row_number函数、Oracle用的是ROWNUM、row_number(),今天主要讲的是MySQL数据库的。
为什么用到分页查询?
1、用户体验、页面显示效果:
在开发过程当中,我们经常需要从数据库中查询数据,然后将数据在客户端显示,如果数据量少的话,可以在一个页面上显示完成,但是如果查询的数据是几百条、上千条数据的时候,全部在一个页面上显示出来,非常影响页面的美观性和用户的体验。所以这就用到分页技术。
2、服务器资源、性能:
当数据量过大时,可能会导致各种各样的问题发生,例如:服务器资源被耗尽,因数据传输量过大而使处理超时,等等。最终都会导致查询无法完成当数据量过大时,可能会导致各种各样的问题发生,例如:服务器资源被耗尽,因数据传输量过大而使处理超时,等等。最终都会导致查询无法完成
打一个比方,有很多很多人要过河,而只有一条船摆渡。若让所有人都上船,肯定会导致沉船(资源耗尽);若换一条超大的船,除了换船要很高的成本外,上船下船也要耗费很长时间。
所以最好的解决方法是,根据船的容量,每次只上一部分人。等这一船人过河以后,再摆渡下一批人。
2.知识剖析
(一)limit用法
select * from tablename limit #{start},#{size}
start是从哪里开始显示
size是每页显示多少条记录
(二)总记录数totalCount
select count(1) from tablename
(三)总页数
totalPage=totalCount/pageSize
(二)需要用到的参数
private int currPage;//当前页数
private int pageSize;//每页显示的记录数
private int totalCount;//总记录数
private int totalPage;//总页数
private List<T> lists;//每页的显示的数据
具体实现过程
1)di
定义PageBean类
package com.pojo;
import java.util.List;
public class PageBean<T> {
private int currPage;//当前页数
private int pageSize;//每页显示的记录数
private int totalCount;//总记录数
private int totalPage;//总页数
private List<T> lists;//每页的显示的数据
public PageBean() {
super();
}
public int getCurrPage() {
return currPage;
}
public void setCurrPage(int currPage) {
this.currPage = currPage;
}
public int getPageSize() {
return pageSize;
}
public void setPageSize(int pageSize) {
this.pageSize = pageSize;
}
public int getTotalCount() {
return totalCount;
}
public void setTotalCount(int totalCount) {
this.totalCount = totalCount;
}
public int getTotalPage() {
return totalPage;
}
public void setTotalPage(int totalPage) {
this.totalPage = totalPage;
}
public List<T> getLists() {
return lists;
}
public void setLists(List<T> lists) {
this.lists = lists;
}
}
2)在mapper中配置相对应sql
<!-- 根据分页数据start 和size查询数据 -->
<select id="findByPage" parameterType="Map" resultMap="paperResultMap">
select
*
from paper
<if test="start!=null and size!=null">
limit #{start},#{size}
</if>
</select>
<!-- 查询用户记录总数 -->
<select id="selectCount" resultType="int">
select count(*) from paper
</select>
<select id="queryAllPaper" resultMap="paperResultMap">
SELECT paper_id,name,number,detail
FROM paper
</select>
3)在service层封装Bean类
@Override
public PageBean<Paper> findByPage(int currentPage) {
HashMap<String, Object> map = new HashMap<String, Object>();
PageBean<Paper> pageBean = new PageBean<Paper>();
//封装当前页数
pageBean.setCurrPage(currentPage);
//每页显示的数据
int pageSize = 8;
pageBean.setPageSize(pageSize);
//封装总记录数
int totalCount = paperDao.selectCount();
pageBean.setTotalCount(totalCount);
//封装总页数
double tc = totalCount;
Double num = Math.ceil(tc / pageSize);//向上取整,除不尽的时候都向上取整
pageBean.setTotalPage(num.intValue());
map.put("start", (currentPage - 1) * pageSize);
map.put("size", pageBean.getPageSize());
//封装每页显示的数据
List<Paper> lists = paperDao.findByPage(map);
pageBean.setLists(lists);
return pageBean;
}
4)在接口中加入需要用到的参数类型
Paper queryById(long id);
List<Paper> queryAllPaper();
int selectCount();
//分页
PageBean<Paper> findByPage(int currentPage);
5)在jsp页面加入判断逻辑和显示
<table border="0" cellspacing="0" cellpadding="0" width="900px">
<tr>
<td class="td2">
<span>第${requestScope.pagemsg.currPage }/ ${requestScope.pagemsg.totalPage}页</span>
<span>总记录数:${requestScope.pagemsg.totalCount } 每页显示:${requestScope.pagemsg.pageSize}</span>
<span>
<c:if test="${requestScope.pagemsg.currPage != 1}">
<a href="${pageContext.request.contextPath }/allPaper?currentPage=1">[首页]</a>
<a href="${pageContext.request.contextPath }/allPaper?currentPage=${requestScope.pagemsg.currPage-1}">[上一页]</a>
</c:if>
<c:if test="${requestScope.pagemsg.currPage != requestScope.pagemsg.totalPage}">
<a href="${pageContext.request.contextPath }/allPaper?currentPage=${requestScope.pagemsg.currPage+1}">[下一页]</a>
<a href="${pageContext.request.contextPath }/allPaper?currentPage=${requestScope.pagemsg.totalPage}">[尾页]</a>
</c:if>
</span>
</td>
</tr>
</table>
</td>
</tr>
</table>
6)因为我用的是SSM框架,在控制类中加如回显分页数据
@RequestMapping(value = "/allPaper", method = RequestMethod.GET)
public String queryAllPaper(@RequestParam(value="currentPage",defaultValue="1",required=false)int currentPage, Model model,Paper paper) {
List<Paper> list = paperService.queryAllPaper();
model.addAttribute("list", list);
model.addAttribute("pagemsg", paperService.findByPage(currentPage));//回显分页数据
return "allPaper";
}
整个流程就完成了。
分页查询核心在于,定义Bean类和也是显示,sql语句是最简单的。
3、常见问题
1.在使用 Math.ceil进行页面查询向上取整的时候需要设置成什么类型?
2.分页利用PageHelper.startPage(page, rows)应该放在哪里?
4.解决方案
1.在使用 Math.ceil进行页面查询向上取整的时候,数据类型转换成double类型
2.分页利用PageHelper.startPage(page, rows)时所放位置的注意事项
可以参考以下博文:https://blog.csdn.net/weixin_41267342/article/details/79151098
5.编码实战
6.扩展思考
1.在使用 Math.ceil进行页面查询向上取整的时候需要设置成什么类型?
在使用 Math.ceil进行页面查询向上取整的时候,数据类型转换成double类型
2.分页利用PageHelper.startPage(page, rows)应该放在哪里?
分页利用PageHelper.startPage(page, rows)时所放位置的注意事项
可以参考以下博文:https://blog.csdn.net/weixin_41267342/article/details/79151098
3.常见数据库分页查询语句有哪些
1.oracle数据库分页
select * from (select a.*,rownum rc from 表名 where rownum<=endrow) a where a.rc>=startrow
2.DB2数据库分页
Select * from (select rownumber() over() as rc,a.* from (select * from 表名 order by列名) as a) where rc between startrow and endrow
3.SQL Server 2000数据库分页
Select top pagesize * from 表名 where 列名 not in(select top pagesize*page 列名 from 表名 order by列名) order by列名
4.SQL Server 2005数据库分页
Select * from (select 列名,row_number() over(order by 列名1) as 别名from 表名) as t where t.列名1>=startrow and t.列名1<=endrow
5.MySQL数据库分页
Select * from 表名 limit startrow,pagesize
(Pagesize为每页显示的记录条数)
6.PostgreSQL数据库分页
Select * from 表名 limit pagesize,offset startrow
(Pagesize为每页显示的记录条数)
7. 参考文献
https://zhidao.baidu.com/question/168096244.html
https://www.cnblogs.com/geningchao/p/6649907.html
https://blog.csdn.net/weixin_41267342/article/details/79151098
8. 更多讨论
分页limit查询效率有点低,有没有什么优化方案或者替换方法?
由于个人目前只用到一些少数据量的查询,就没有深入学习,但是这里有一篇不错的博文,大家有兴趣可以了解一下。
https://www.cnblogs.com/geningchao/p/6649907.html
今天的分享就到这里啦,欢迎大家点赞、转发、留言、拍砖~