-
2022-04-08 10:37:13
一. 面试题及剖析
1. 今日面试题
MySQL如何实现分页效果?
为什么MySQL分页查询,越到后面速度越慢?
三百万条数据怎么做分页查询;
你用过分页插件PageHepler吗?
介绍一下PageHelper吧
2. 题目剖析
在之前的文章中,壹哥已经给大家讲解了好几个SQL语句中的关键字,比如SELECT查询相关的关键字,今天壹哥会继续给大家分析SQL语句中的一些常用关键字,今天主要是讲解与分页相关的关键字--limit。通过这个关键字,壹哥带大家复习MySQL如何实现分页,以及分页的底层实现原理,这既是我们开发时常用的技能,又是面试时常考的内容。
二. MySQL分页
1. limit语法
在SQL语句中&#x
更多相关内容 -
分页js文件
2018-05-11 22:00:59分页js、代码看博客分页js、代码看博客分页js、代码看博客分页js、代码看博客 -
elasticsearch聚合后分页
2018-12-16 14:45:55方法如果传总页数了,es就不用查询总页数,直接通过开始位置到结束位置取数即可 -
Vue.js 组件实现分页效果
2017-03-14 14:09:42为了练习vue.js 之前做了一个vue.js前端分页效果,后面看到vue.js组件内容,就试着把这个功能写成一个简单组件,向组件元素传递一个object参数,包含分页数据,显示的列名信息,分页信息,组件提供一个事件,传递给... -
kettle循环分页迁移数据的完整例子,一次迁移1w数据无压力
2018-09-09 14:46:00kettle写的循环分页迁移数据的例子,迁移了36w数据,速度飞快,平均cpu使用只有19%。数据库表是运营商号段数据,网上有,比较大就不放上来了。 -
MyBatisplus分页插件
2022-05-04 15:29:35文章目录一、后台分页配置1. 配置分页插件2. 编写分页代码3. 测试二、自定义查询2.1. 自定义接口2.2. 自定义查询2.3. 测试自定义分页 一、后台分页配置 MyBatis Plus自带分页插件(即BaseMapper接口中的selectPage()...一、后台分页配置
MyBatis Plus自带分页插件(即BaseMapper接口中的selectPage()方法),只要简单的配置即可实现分页功能,具体步骤如下:
1. 配置分页插件
新创一个配置类,在配置类里面配置分页插件
package com.gblfy.flowable.config; import com.baomidou.mybatisplus.annotation.DbType; import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; /** * MyBatisPlus 分页插件配置 * * @Author gblfy * @Date 2022-05-04 14:41 **/ @Configuration public class MyBatisPlusPaginationInnerConfig { /** * 分页插件(官网最新) */ @Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); return interceptor; } }
2. 编写分页代码
分页的所有数据都在userPage对象中封装着,所以可以调用userPage对象的一系列方法对分页数据进行操作。
package com.gblfy.flowable.service.impl; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.gblfy.flowable.entity.SysUser; import com.gblfy.flowable.mapper.SysUserMapper; import com.gblfy.flowable.service.SysUserService; import com.gblfy.flowable.tools.pager.PagerModel; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.List; /** * <p> * 用户信息表 服务实现类 * </p> * * @author gblfy * @since 2022-05-04 */ @Slf4j @Service public class SysUserServiceImpl implements SysUserService { @Autowired private SysUserMapper userMapper; @Override public PagerModel<SysUser> list(Page<SysUser> page, QueryWrapper<SysUser> queryWrapper) { Page<SysUser> userIPage = userMapper.selectPage(page, queryWrapper); // 分页的所有数据都在userPage对象中封装着 // 获取总页数 long pages = userIPage.getPages(); //一页显示几条数据 long size = userIPage.getSize(); // 获取当前页 long current = userIPage.getCurrent(); // 获取当前页数据集合 List<SysUser> records = userIPage.getRecords(); // 获取总记录数 long total = userIPage.getTotal(); // 当前页是否有下一页 boolean hasNext = userIPage.hasNext(); // 当前页是否有上一页 boolean hasPrevious = userIPage.hasPrevious(); System.out.println("总页数pages=" + pages); System.out.println("当前页current=" + current); System.out.println("当前页显示几条数据size=" + size); System.out.println("当前页数据集合records=" + records); System.out.println("总记录数total=" + total); System.out.println("是否有下一页hasNext=" + hasNext); System.out.println("是否有上一页hasPrevious=" + hasPrevious); return new PagerModel<>(userIPage.getTotal(), records); } @Override public Page<SysUser> listPage(Page<SysUser> page, QueryWrapper<SysUser> queryWrapper) { return userMapper.selectPage(page, queryWrapper); } }
3. 测试
当前数据库的user表中有14条记录,设置当前页数为1,每页记录数为10。
如图:
controller
package com.gblfy.flowable.controller; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.gblfy.flowable.entity.SysUser; import com.gblfy.flowable.service.SysUserService; import com.gblfy.flowable.tools.pager.PagerModel; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; /** * MyBatisPlus 分页测试 * * @Author gblfy * @Date 2022-05-04 15:32 **/ @RestController @RequestMapping("/page") public class MyBatisPlusPaginateController { @Autowired private SysUserService userService; @GetMapping("/list") public PagerModel<SysUser> list(@RequestParam(value = "keyword", defaultValue = "") String keyword, @RequestParam(value = "pageNum", defaultValue = "1") Integer pageNum, @RequestParam(value = "pageSize", defaultValue = "5") Integer pageSize) { QueryWrapper<SysUser> queryWrapper = new QueryWrapper<>();//条件构造器 queryWrapper.like("user_name", keyword);//模糊查询Like Page<SysUser> page = new Page(pageNum, pageSize);//分页插件 return userService.list(page, queryWrapper);//查询数据 } @GetMapping("/listPage") public Page<SysUser> listPage(@RequestParam(value = "keyword", defaultValue = "") String keyword, @RequestParam(value = "pageNum", defaultValue = "1") Integer pageNum, @RequestParam(value = "pageSize", defaultValue = "5") Integer pageSize) { QueryWrapper<SysUser> queryWrapper = new QueryWrapper<>();//条件构造器 queryWrapper.like("user_name", keyword);//模糊查询Like Page<SysUser> page = new Page(pageNum, pageSize);//分页插件 return userService.listPage(page, queryWrapper);//查询数据 } }
默认返回Page基本可以满足,如果自定义返回封装,参考以下案例即可
package com.gblfy.flowable.tools.pager; import lombok.Builder; import lombok.Data; import java.io.Serializable; import java.util.ArrayList; import java.util.List; /** * 分页 * * @author gblfy * @date 2022-05-03 **/ @Data @Builder(toBuilder = true) public class PagerModel<T> implements Serializable { private static final long serialVersionUID = 4804053559968742915L; /** * 总记录数 */ private long total; /** * 每页的查询结果集 */ private List<T> rows = new ArrayList(); /** * 获取总页数 */ private long pages; /** * 获取当前页 */ private long current; /** * 当前页显示几条数据 */ private long size; /** * 当前页是否有下一页 */ private boolean hasNext; /** * 当前页是否有上一页 */ private boolean hasPrevious; public PagerModel() { } public PagerModel(long total, List<T> rows) { this.total = total; this.rows = rows; } public PagerModel(long total, List<T> rows, long pages, long current) { this.total = total; this.rows = rows; this.pages = pages; this.current = current; } public PagerModel(long total, List<T> rows, long pages, long current, long size) { this.total = total; this.rows = rows; this.pages = pages; this.current = current; this.size = size; } public PagerModel(long total, List<T> rows, long pages, long current, boolean hasNext, boolean hasPrevious) { this.total = total; this.rows = rows; this.pages = pages; this.current = current; this.hasNext = hasNext; this.hasPrevious = hasPrevious; } public PagerModel(long total, List<T> rows, long pages, long current, long size, boolean hasNext, boolean hasPrevious) { this.total = total; this.rows = rows; this.pages = pages; this.current = current; this.size = size; this.hasNext = hasNext; this.hasPrevious = hasPrevious; } }
二、自定义查询
2.1. 自定义接口
如果想自定义查询那么在UserMapper.java里面写个方法
Page<User> selectPageVo(@Param("page") Page<User> page,@Param("age") Integer age);
2.2. 自定义查询
UserMapper.xml文件的查询语句
<select id="selectPageVo" resultType="com.mybatis_plus.bean.User"> SELECT id,name,age,email FROM user WHERE age>#{age} </select>
2.3. 测试自定义分页
@Test void test02(){ //测试自定义分页 Page<User> page=new Page<>(1,3); userMapper.selectPageVo(page,20);//调用自定义的查询 System.out.println(page.getRecords());//获取当前页数据 3条记录 System.out.println(page.getSize());//获取每页的条数 3 System.out.println(page.getCurrent()); //获取当前页码 1 System.out.println(page.getPages());//获取总页数 2 System.out.println(page.getTotal());//获取总记录数 4 System.out.println(page.hasNext());//获取有没有下一页 true System.out.println(page.hasPrevious());//获取是否有上一页 false }
-
mybatis分页查询
2015-12-28 00:04:59mybatis分页查询,spring + maven + mybatis实现分页查询源码 -
iscroll移动app滚动分页demo
2015-07-08 08:18:39iscroll移动app滚动分页demo,上拉刷新,下拉加载更多。 -
php 和 mysql 实现 分页
2018-07-05 17:56:55php 和 mysql 进行分页,php 和 mysql 进行分页,php 和 mysql 进行分页,php 和 mysql 进行分页,php 和 mysql 进行分页,php 和 mysql 进行分页,php 和 mysql 进行分页,php 和 mysql 进行分页,php 和 ... -
mybatis-plus分页查询详解
2022-07-14 16:43:58本文主要对mybatis-plus分页查询的原理和使用进行了详细介绍。文章目录
前言
例如:随着人工智能的不断发展,机器学习这门技术也越来越重要,很多人都开启了学习机器学习,本文就介绍了机器学习的基础内容。
一、官方文档
Mybatis-Plus分页插件:https://baomidou.com/pages/97710a/
PageHelper分页插件:https://pagehelper.github.io/
Tip⚠️:
官网链接,第一手资料。二、内置的分页方法
1、内置方法
在
Mybatis-Plus
的BaseMapper
中,已经内置了2个支持分页的方法:public interface BaseMapper<T> extends Mapper<T> { <P extends IPage<T>> P selectPage(P page, @Param("ew") Wrapper<T> queryWrapper); <P extends IPage<Map<String, Object>>> P selectMapsPage(P page, @Param("ew") Wrapper<T> queryWrapper); …… }
2、selectPage单元测试
使用selectPage方法分页查询年纪age = 13的用户。
@Test public void testPage() { System.out.println("----- selectPage method test ------"); //分页参数 Page<User> page = Page.of(1,10); //queryWrapper组装查询where条件 LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>(); queryWrapper.eq(User::getAge,13); userMapper.selectPage(page,queryWrapper); page.getRecords().forEach(System.out::println); }
执行结果:
查询出了表中满足条件的所有记录,说明默认情况下,selectPage方法并不能实现分页查询。3、PaginationInnerInterceptor分页插件配置
mybatis-plus中的分页查询功能,需要PaginationInnerInterceptor分页插件的支持,否则分页查询功能不能生效。
@Configuration public class MybatisPlusConfig { /** * 新增分页拦截器,并设置数据库类型为mysql */ @Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); return interceptor; } }
再次执行单元测试:
先执行count查询查询满足条件的记录总数,然后执行limit分页查询,查询分页记录,说明分页查询生效。三、分页原理分析
查看PaginationInnerInterceptor拦截器中的核心实现:
//select查询请求的前置方法 public void beforeQuery(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException { //根据请求参数来判断是否采用分页查询,参数中含有IPage类型的参数,则执行分页 IPage<?> page = (IPage)ParameterUtils.findPage(parameter).orElse((Object)null); if (null != page) { boolean addOrdered = false; String buildSql = boundSql.getSql(); List<OrderItem> orders = page.orders(); if (CollectionUtils.isNotEmpty(orders)) { addOrdered = true; buildSql = this.concatOrderBy(buildSql, orders); } //根据page参数,组装分页查询sql Long _limit = page.maxLimit() != null ? page.maxLimit() : this.maxLimit; if (page.getSize() < 0L && null == _limit) { if (addOrdered) { PluginUtils.mpBoundSql(boundSql).sql(buildSql); } } else { this.handlerLimit(page, _limit); IDialect dialect = this.findIDialect(executor); Configuration configuration = ms.getConfiguration(); DialectModel model = dialect.buildPaginationSql(buildSql, page.offset(), page.getSize()); MPBoundSql mpBoundSql = PluginUtils.mpBoundSql(boundSql); List<ParameterMapping> mappings = mpBoundSql.parameterMappings(); Map<String, Object> additionalParameter = mpBoundSql.additionalParameters(); model.consumers(mappings, configuration, additionalParameter); mpBoundSql.sql(model.getDialectSql()); mpBoundSql.parameterMappings(mappings); } } }
再来看看ParameterUtils.findPage()方法的实现:
//发现参数中的IPage对象 public static Optional<IPage> findPage(Object parameterObject) { if (parameterObject != null) { //如果是多个参数,会转为map对象;只要任意一个value中包含IPage类型的对象,返回IPage对象 if (parameterObject instanceof Map) { Map<?, ?> parameterMap = (Map)parameterObject; Iterator var2 = parameterMap.entrySet().iterator(); while(var2.hasNext()) { Entry entry = (Entry)var2.next(); if (entry.getValue() != null && entry.getValue() instanceof IPage) { return Optional.of((IPage)entry.getValue()); } } //如果只有单个参数,且类型为IPage,则返回IPage对象 } else if (parameterObject instanceof IPage) { return Optional.of((IPage)parameterObject); } } return Optional.empty(); }
小结:
mybatis-plus分页查询的实现原理:
1、由分页拦截器PaginationInnerInterceptor
拦截所有查询请求,在执行查询前判断参数中是否包含IPage类型的参数。
2、如果包含IPage类型的参数,则根据分页信息,重新组装成分页查询的SQL。四、自定义分页方法
搞清楚mybatis-plus中分页查询的原理,我们来自定义分页查询方法。
这里我使用的是
mybatis-plus 3.5.2
的版本。<dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.5.2</version> </dependency>
在UserMapper中新增
selectPageByDto
方法。public interface UserMapper extends CommonMapper<User> { /** * 不分页dto条件查询 * @param userDto * @return */ List<User> selectByDto(@Param("userDto") UserDto userDto); /** * 支持分页的dto条件查询 * @param page * @param userDto * @return */ IPage<User> selectPageByDto(IPage<User> page,@Param("userDto") UserDto userDto); }
说明:
1、mybatis-plus中分页接口需要包含一个IPage类型的参数。
2、多个实体参数,需要添加@Param参数注解,方便在xml中配置sql时获取参数值。UserMapper.xml中的分页sql配置:
这里由于selectByDto和selectPageByDto两个方法都是根据dto进行查询,
sql语句完全一样,所以将相同的sql抽取了出来,然后用include标签去引用。<sql id="selectByDtoSql"> select * from user t <where> <if test="userDto.name != null and userDto.name != '' "> AND t.name like CONCAT('%',#{userDto.name},'%') </if> <if test="userDto.age != null"> AND t.age = #{userDto.age} </if> </where> </sql> <select id="selectByDto" resultType="com.laowan.mybatis_plus.model.User"> <include refid="selectByDtoSql"/> </select> <select id="selectPageByDto" resultType="com.laowan.mybatis_plus.model.User"> <include refid="selectByDtoSql"/> </select>
1、2种分页写法
- 方式一:
Page对象既作为参数,也作为查询结果接受体
@Test public void testSelectPageByDto() { System.out.println("----- SelectPageByDto method test ------"); //分页参数Page,也作为查询结果接受体 Page<User> page = Page.of(1,10); //查询参数 UserDto userDto = new UserDto(); userDto.setName("test"); userMapper.selectPageByDto(page,userDto); page.getRecords().forEach(System.out::println); }
- 方式二:
Page作为参数,用一个新的IPage对象接受查询结果。
@Test public void testSelectPageByDto() { System.out.println("----- SelectPageByDto method test ------"); //查询参数 UserDto userDto = new UserDto(); userDto.setName("test"); //PageDTO.of(1,10)对象只作为查询参数, IPage<User> page = userMapper.selectPageByDto(PageDTO.of(1,10),userDto); page.getRecords().forEach(System.out::println); }
下面是官网的一些说明:
这是官网针对自定义分页的说明。个人建议:如果定义的方法名中包含Page说明是用来分页查询的,返回结果尽量用IPage,而不要用List。防止出现不必要的错误,也更符合见名之一和单一指责原则。
2、利用page.convert方法实现Do到Vo的转换
public IPage<UserVO> list(PageRequest request) { IPage<UserDO> page = new Page(request.getPageNum(), request.pageSize()); LambdaQueryWrapper<UserDO> qw = Wrappers.lambdaQuery(); page = userMapper.selectPage(page, qw); return page.convert(u->{ UserVO v = new UserVO(); BeanUtils.copyProperties(u, v); return v; }); }
五、分页插件 PageHelper
很多人已经习惯了在mybatis框架下使用PageHelper进行分页查询,在mybatis-plus框架下依然也可以使用,和mybatis-plus框架自带的分页插件没有明显的高下之分。
个人认为mybatis-plus的分页实现可以从方法命名、方法传参方面更好的规整代码。而PageHelper的实现对代码的侵入性更强,不符合单一指责原则。
推荐
在同一个项目中,只选用一种分页方式,统一代码风格
。PageHelper的使用:
1.引入maven依赖
<dependency> <groupId>com.github.pagehelper</groupId> <artifactId>pagehelper</artifactId> <version>最新版本</version> </dependency>
2.PageHelper分页查询
代码如下(示例):
//获取第1页,10条内容,默认查询总数count PageHelper.startPage(1, 10); List<Country> list = countryMapper.selectAll(); //用PageInfo对结果进行包装 PageInfo page = new PageInfo(list);
总结
本文主要对mybatis-plus分页查询的原理和使用进行了详细介绍。
1、要开启mybatis-plus分页查询功能首先需要配置PaginationInnerInterceptor分页查询插件。
2、PaginationInnerInterceptor分页查询插件的实现原理是:拦截所有查询请求,分析查询参数中是否包含IPage类型的参数。如果有则根据分页信息和数据库类型重组sql。
3、提供了2种分页查询的写法。
4、和经典的PageHelper分页插件进行了对比。两者的使用都非常简单,在单一项目中任选一种,统一代码风格即可。
- 方式一:
-
使用Bootstrap实现分页,并且当页码过多时使用省略号
2016-01-08 21:18:37使用Bootstrap实现分页,并且当页码过多时使用省略号,这篇文章有样式的简单演示:https://blog.csdn.net/u013025627/article/details/50485327 样式只是自己的简单样式,不同的项目有不同的样式风格,只是提供分页... -
jquery带省略号的分页
2015-06-29 15:03:06jquery带省略号分页,已经亲自测试过,最近公司要求的做的分页效果就是用的这片代码 -
.net 分页代码,实现真分页。很不错的资源
2013-11-10 23:40:26.net 分页代码,实现真分页。很不错的资源。不再使用传统的假分页,使用真分页提高系统性能 -
分页功能的分析与实现
2022-04-15 12:08:41主要讲解了分页功能的分析与实现。两种实现方式「物理分页」和「逻辑分页」。以及具体讲解了如何在javaWeb项目和使用MyBatis框架的项目的实现。
前言
这篇博客是用来记录自己所理解的分页功能,后续还会有补充,如果对内容有任何疑问,欢迎一起交流学习。
一、什么是分页
分页就是让页面可以显示指定条数的数据。通过分页功能,可以更容易的管理数据,查看数据。
通过上述描述,就可以想到,大体的分页方式就是,通过各种查询,各种处理,然后将该指定条数的数据发送到前台进行显示。
二、分页的实现
1. 分页方式
-
逻辑分页
先把所有数据都查出来,然后通过Java程序处理将指定条数据发送到前端进行显示。SQL语句简单,但不适合数据量大的分页。 -
物理分页
利用SQL语句查询到指定条数据,发送到前端进行显示。当数据量较大时使用物理分页效率更高,但SQL语句较为复杂。
2. 页面跳转的几种方式
- 显示每一页的下标,通过点击下标,跳转到对应的页面。
- 通过点击 首页、上一页、下一页、尾页,进行跳转
- 通过搜索页号进行跳转
- 通过select下拉列表的选择进行跳转
3. 分页的实现——分页工具类
分页工具类里定义了一些用于分页的属性和方法。主要是通过分页工具类来实现分页功能的。
3.1 分页工具类——PageUtil.java
package com.dao; public class PageUtil { // 每页显示的条数 private int pageSize; // 总共的条数 private int recordCount; // 当前页面 private int currentPage; //总页数 public int pageCount; //上一页的最后一条记录 private int start; //当前页的最后一条记录 private int end; // 获取上一页的最后一条记录 public int getStart() { start=(currentPage - 1) * pageSize; return start; } //为mysql写的 select * from table limit start,end; //limit是限制查询从start+1开始,最多查询end条数据 public int getEnd() { end=pageSize; return end; } // 构造方法 public PageUtil(int pageSize, int recordCount, int currentPage) { this.pageSize = pageSize; this.recordCount = recordCount; setCurrentPage(currentPage); } // 构造方法 public PageUtil(int pageSize, int recordCount) { this(pageSize, recordCount, 1); } public PageUtil() { super(); // TODO Auto-generated constructor stub } // 总页数 public int getPageCount() { // 总条数/每页显示的条数=总页数 int size = recordCount / pageSize; // 最后一页的条数 int mod = recordCount % pageSize; // 看需不需要多余的页,也就是最后一页 if (mod != 0) size++; this.pageCount=recordCount == 0 ? 1 : size; return this.pageCount; } // 上一页的最后一条记录数。包含,起始索引为0 public int getFromIndex() { // System.out.println("from index:"+(currentPage-1) * pageSize); return (currentPage - 1) * pageSize; } // 本页的最后一条记录数。不包含 public int getToIndex() { // System.out.println("to index:"+Math.min(recordCount, currentPage * // pageSize)); return Math.min(recordCount, currentPage * pageSize); } // 得到当前页 public int getCurrentPage() { return currentPage; } // 设置当前页 public void setCurrentPage(int currentPage) { int validPage = currentPage <= 0 ? 1 : currentPage; validPage = validPage > getPageCount() ? getPageCount() : validPage; this.currentPage = validPage; } // 得到每页显示的条数 public int getPageSize() { return pageSize; } // 设置每页显示的条数 public void setPageSize(int pageSize) { this.pageSize = pageSize; } // 得到总共的条数 public int getRecordCount() { return recordCount; } // 设置总共的条数 public void setRecordCount(int recordCount) { this.recordCount = recordCount; } }
3.2 相关参数
- 记录总数:recordCount = 通过后台查询数据库获取「一条数据就是一条记录」
- 页面总数:pageCount = recordCount % pageSize == 0 ? (recordCount / pageSize):(recordCount / pageSize + 1)
如果recordCount % pageSize != 0,说明最后一页还多余出几条数据,所以就需要新增一页来存放 - 页面大小:pageSize = 自己设定一页到底要显示多少条数据
- 当前页号:currentPage = 默认值是1,是前台需要向后台传递的参数之一
- 前一页:currentPage - 1
- 后一页:currentPage + 1
- 上一页的最后一条记录数:start = pageSize * (currentPage - 1)
- 当前页的最后一条记录数:end = min(pageCount, pageSize* currentPage)
如果该页不是最后一页,当前页最后一条记录数一定是 currentPage * pageSize
如果该页是最后一页,当前页最后一条记录数最大就是 currentPage * pageSize;如果不是满页,则该页的最后一条记录数就是总记录数
所以要取最小值
最重要的三个参数:记录总数、页面大小、当前页号
通过记录总数就可以知道一共有多少条数据
通过页面大小就可以知道一共有多少个页面
通过当前页号+页面大小,就可以知道当前页有哪些内容,前一页有哪些内容,后一页有哪些内容三、JavaWeb项目分页实现
案例:对查询到的部门信息进行分页,每页显示3条数据。前台页面
DepartmentPage.jsp
,后台页面SearchDepartmentPageServlet
。1. 逻辑分页
DepartmentPage.jsp
作用:
①用于显示分页后的部门信息
②向后台传递「要查询什么信息——部门信息」和「当前页面的页号」SearchDepartmentPageServlet
作用:
①查询所有部门的信息,将指定区间的部门信息传递给前台。(连接数据库后查询到所有的部门信息,然后通过Java代码将指定区间的数据发送到前台显示)
DepartmentPage.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <c:set value="${pageContext.request.contextPath}" var="path"></c:set> <html> <head> <title>Title</title> <%--引入jQuery库--%> <script src="${path}/js/jquery.js"></script> <%--定义js脚本,向后台传递当前页号和部门名称--%> <script> function formSubmit(currentPage) { $('input[name="currentPage"]').val(currentPage); $('form:first').submit(); } </script> </head> <body> <%--通过查询来显示指定数据--%> <form action="${path}/SearchDepartmentPageServelt"> <label>部门名称</label> <%--查询条件--%> <input type="text" name="departmentName" value="${param.departmentName}"> <%--当前页数--%> <input type="hidden" name="currentPage" value="1"> <input type="submit" value="查找"> </form> <%--要显示的部门信息--%> <table> <tr> <th>部门编号</th> <th>部门名称</th> <th>部门地址</th> </tr> <%--这里根据后台的查询数据循环生成表格里的数据--%> <c:forEach items="${departments}" var="department"> <tr> <th>${department.departmentId}</th> <th>${department.departmentName}</th> <th>${department.locationName}</th> </tr> </c:forEach> </table> <%--数据显示--%> <div> <label>共${pageUtil.recordCount}条数据,每页显示${pageUtil.pageSize}条数据,共${pageUtil.pageCount}页,当前是第${pageUtil.currentPage}页</label> </div> <%--用来进行页面跳转--%> <%--第一次查询后就已经获取到pageUtil对象,然后就可以使用pageUtil对象里的属性了--%> <div> <a href="#" onclick="formSubmit(1)" id="first">首页</a> <a href="#" onclick="formSubmit(${pageUtil.currentPage - 1})" id="prev">上一页</a> <a href="#" onclick="formSubmit(${pageUtil.currentPage + 1})" id="next">下一页</a> <a href="#" onclick="formSubmit(${pageUtil.pageCount})" id="last">尾页</a> <label>跳转到</label> <%--输入框填写页数--%> <input type="text" id="pageNum"> <%--根据输入框中的页数,进行跳转--%> <input type="button" value="Go" onclick="formSubmit($('#pageNum').val())"> </div> </body> </html>
SearchDepartmentPageServlet
package com.servlets; import com.dao.PageUtil; import com.service.DepartmentService; import com.vo.Department; import javax.servlet.*; import javax.servlet.http.*; import javax.servlet.annotation.*; import java.io.IOException; import java.util.ArrayList; import java.util.List; @WebServlet(name = "SearchDepartmentPageServlet", value = "/SearchDepartmentPageServlet") public class SearchDepartmentPageServlet extends HttpServlet { private DepartmentService departmentService = new DepartmentService(); @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 从jsp页面接收到的参数 String departmentName = request.getParameter("departmentName"); int currentPage = Integer.parseInt(request.getParameter("currentPage")); // 查询到所有的部门信息 List<Department> departmentList = departmentService.selectByDepartmentName(departmentName); // 创建页面划分对象 PageUtil pageUtil = new PageUtil(3, departmentList.size(), currentPage); // 创建一个部门集合,用来存放要显示的部门信息。(之前是将获取到的集合对象直接转发,现在要从对象中获取指定条数的对象) List<Department> departments = new ArrayList<>(); for (int i = pageUtil.getFromIndex(); i < pageUtil.getToIndex(); i++) { departments.add(departmentList.get(i)); } // 将部门和页面工具对象请求转发到指定的页面 request.setAttribute("departments", departments); request.setAttribute("pageUtil", pageUtil); request.getRequestDispatcher("DepartmentPage.jsp").forward(request, response); } @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } }
DepartmentDao.java
// 通过名字查询部门 public List<Department> selectByDepartmentName(String departmentName){ String sql = "SELECT * FROM departments WHERE DEPARTMENT_NAME LIKE ?"; Object[] objects = {"%"+departmentName+"%"}; RowMapper<Department> rm = (rs)->{ Department department = new Department(); try { department.setDepartmentId(rs.getInt("DEPARTMENT_ID")); department.setDepartmentName(rs.getString("DEPARTMENT_NAME")); department.setLocationName(rs.getString("LOCATION_NAME")); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } return department; }; return Dbutil.executeQuery(sql, objects, rm); }
DepartmentService.java
private DepartmentDao departmentDao = new DepartmentDao(); // 通过名字查询部门 public List<Department> selectByDepartmentName(String departmentName){ return departmentDao.selectByDepartmentName(departmentName); }
2. 物理分页
DepartmentPage.jsp
作用:
①用于显示分页后的部门信息
②向后台传递「要查询什么信息——部门信息」和「当前页面的页号」- dao层的作用:
①通过SQL语句查询要显示在页面的部门信息
②也需要通过SQL语句查询部门信息的总记录数 SearchDepartmentPageServlet
作用:
①负责将要显示的部门信息发送给前台
②当然也需要将总记录数发送给前台,用于分页计算和前台显示
DepartmentPage.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <c:set value="${pageContext.request.contextPath}" var="path"></c:set> <html> <head> <title>Title</title> <%--引入jQuery库--%> <script src="${path}/js/jquery.js"></script> <%--定义js脚本,向后台传递当前页号和部门名称--%> <script> function formSubmit(currentPage) { $('input[name="currentPage"]').val(currentPage); $('form:first').submit(); } </script> </head> <body> <%--通过查询来显示指定数据--%> <form action="${path}/SearchDepartmentPageServelt2"> <label>部门名称</label> <%--查询条件--%> <input type="text" name="departmentName" value="${param.departmentName}"> <%--当前页数--%> <input type="hidden" name="currentPage" value="1"> <input type="submit" value="查找"> </form> <%--要显示的部门信息--%> <table> <tr> <th>部门编号</th> <th>部门名称</th> <th>部门地址</th> </tr> <%--这里根据后台的查询数据循环生成表格里的数据--%> <c:forEach items="${departments}" var="department"> <tr> <th>${department.departmentId}</th> <th>${department.departmentName}</th> <th>${department.locationName}</th> </tr> </c:forEach> </table> <%--数据显示--%> <div> <label>共${pageUtil.recordCount}条数据,每页显示${pageUtil.pageSize}条数据,共${pageUtil.pageCount}页,当前是第${pageUtil.currentPage}页</label> </div> <%--用来进行页面跳转--%> <%--第一次查询后就已经获取到pageUtil对象,然后就可以使用pageUtil对象里的属性了--%> <div> <a href="#" onclick="formSubmit(1)" id="first">首页</a> <a href="#" onclick="formSubmit(${pageUtil.currentPage - 1})" id="prev">上一页</a> <a href="#" onclick="formSubmit(${pageUtil.currentPage + 1})" id="next">下一页</a> <a href="#" onclick="formSubmit(${pageUtil.pageCount})" id="last">尾页</a> <label>跳转到</label> <%--输入框填写页数--%> <input type="text" id="pageNum"> <%--根据输入框中的页数,进行跳转--%> <input type="button" value="Go" onclick="formSubmit($('#pageNum').val())"> </div> </body> </html>
SearchDepartmentPageServlet2.java
package com.servlets; import com.dao.PageUtil; import com.service.DepartmentService; import com.vo.Department; import javax.servlet.*; import javax.servlet.http.*; import javax.servlet.annotation.*; import java.io.IOException; import java.util.List; @WebServlet(name = "SearchDepartmentPageServelt2", value = "/SearchDepartmentPageServelt2") public class SearchDepartmentPageServelt2 extends HttpServlet { private DepartmentService departmentService = new DepartmentService(); @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String departmentName = request.getParameter("departmentName"); int currentPage = Integer.parseInt(request.getParameter("currentPage")); PageUtil pageUtil = new PageUtil(3, departmentService.selectByDepartmentName(departmentName).size(), currentPage); List<Department> departments = departmentService.selectLimitDepartment(departmentName, pageUtil.getStart(), pageUtil.getEnd()); request.setAttribute("pageUtil", pageUtil); request.setAttribute("departments", departments); request.getRequestDispatcher("DepartmentPage.jsp").forward(request, response); } @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } }
DepartmentDao.java
// 通过名字查询部门 public List<Department> selectByDepartmentName(String departmentName){ String sql = "SELECT * FROM departments WHERE DEPARTMENT_NAME LIKE ?"; Object[] objects = {"%"+departmentName+"%"}; RowMapper<Department> rm = (rs)->{ Department department = new Department(); try { department.setDepartmentId(rs.getInt("DEPARTMENT_ID")); department.setDepartmentName(rs.getString("DEPARTMENT_NAME")); department.setLocationName(rs.getString("LOCATION_NAME")); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } return department; }; return Dbutil.executeQuery(sql, objects, rm); } // *****************这个是重点***************** // 通过名字查询部门 public List<Department> selectLimitDepartment(String departmentName, int start, int end){ String sql = "SELECT * FROM departments WHERE DEPARTMENT_NAME LIKE ? limit ?, ?"; Object[] objects = {"%"+departmentName+"%", start, end}; RowMapper<Department> rm = (rs)->{ Department department = new Department(); try { department.setDepartmentId(rs.getInt("DEPARTMENT_ID")); department.setDepartmentName(rs.getString("DEPARTMENT_NAME")); department.setLocationName(rs.getString("LOCATION_NAME")); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } return department; }; return Dbutil.executeQuery(sql, objects, rm); }
DepartmentService.java
private DepartmentDao departmentDao = new DepartmentDao(); // 通过名字查询部门 public List<Department> selectByDepartmentName(String departmentName){ return departmentDao.selectByDepartmentName(departmentName); } // 通过名字查询部门 public List<Department> selectLimitDepartment(String departmentName, int start, int end){ return departmentDao.selectLimitDepartment(departmentName, start, end); }
四、使用MyBatis框架实现分页
这里没有使用前端页面来展示分页后的内容,而是通过在控制台打印查询到的分页信息来显示分页内容。下面用两个案例来介绍分页功能。
1. 分页显示班级信息
这里使用的是物理分页,需要做三件事来实现分页:
①从数据库中查出要显示数据的总记录数
②从数据库中查出要显示的数据集合
③分页工具类对象指定页面大小、获取①中的页面总数、指定当前是第几页即可1.1 ClazzMapper.java
// 查询到记录总数,就是一共有多少条班级信息 int selectCount(); // 根据分页工具类进行分页,获取到分页后要显示的班级信息 List<Clazz> selectPage(@Param("page") PageUtil pageUtil);
1.2 ClazzMapper.xml
<!--查询数据库一共有多少条记录--> <select id="selectCount" resultType="int"> select count(*) from clazz </select> <!--物理分页--> <select id="selectPage" resultType="com.bean.Clazz"> select <include refid="base_info"></include> from clazz limit #{page.start}, #{page.end} </select>
1.3 TestClazz.java
@Test public void testSelectPage() { // 这里输出分页信息 int count = this.clazzService.selectCount(); PageUtil pageUtil = new PageUtil(3, count, 3); System.out.println("共"+pageUtil.pageCount+"页"); System.out.println("当前是第"+pageUtil.getCurrentPage()+"页"); System.out.println("共有"+pageUtil.getRecordCount()+"条数据"); // 这里输出分页后的班级信息 List<Clazz> clazzes = this.clazzService.selectPage(pageUtil); for (int i=0; i<clazzes.size(); i++) { Clazz clazz = clazzes.get(i); System.out.println(clazz.getId() + "\t" + clazz.getClassname()); } }
2. 根据条件查询学生信息进行分页
这里也是用的是物理分页,需要做三件事来实现分页:
①查询满足条件的记录总数
②查询满足条件的要显示的数据集合
③分页工具类对象中指定页面大小、记录总数、当前页数2.1 StudentMapper.java
// 根据条件查询学生的数量(不需要使用爱好做条件),查询总记录数 int selectCount(Student student); // 根据条件查询学生的信息,实现分页 List<Student> selectPage(@Param("student") Student student, @Param("page") PageUtil page);
2.2 StudentMapper.xml
<!--根据条件查询出记录总数--> <select id="selectCount" resultType="int"> select count(*) from student <where> <if test="name != null"> name like "%"#{name}"%" </if> <if test="sex != null"> and sex = #{sex} </if> <if test="birthday != null"> and birthday = #{birthday} </if> <if test="age != null and age > 0"> and age = #{age} </if> <if test="classid != null and classid > 0"> and classid = #{classid} </if> </where> </select> <!--根据条件查询出要显示的数据集合--> <select id="selectPage" resultMap="baseMap"> select <include refid="Base_Column_List"></include> from student <where> <if test="student.name != null"> name like "%"#{student.name}"%" </if> <if test="student.sex != null"> and sex = #{student.sex} </if> <if test="student.birthday != null"> and birthday = #{student.birthday} </if> <if test="student.age != null and student.age > 0"> and age = #{student.age} </if> <if test="student.classid != null and student.classid > 0"> and classid = #{student.classid} </if> </where> limit #{page.start}, #{page.end} </select>
TestStudentMapper.java
public void testSelectPage() { // 自定义查询条件 Student student = new Student(); student.setName("a"); student.setSex("man"); // 输出分页信息 int count = this.studentService.selectCount(student); PageUtil pageUtil = new PageUtil(3, count, 2); System.out.println("共"+pageUtil.pageCount+"页"); System.out.println("当前是第"+pageUtil.getCurrentPage()+"页"); System.out.println("共有"+pageUtil.getRecordCount()+"条数据"); // 输出要显示的数据集合 List<Student> students = this.studentService.selectPage(student, pageUtil); for (int i=0; i < students.size(); i++) { System.out.println(students.get(i).getName() + "\t" + students.get(i).getSex()); } }
五、使用MyBatis框架的分页插件实现分页
自问自答
- 为什么点击页号后可以跳转到不同的页面?
其实没有跳转到不同的页面,而是一直都在同一个页面,只是显示的内容不同。根据页号查询到的信息不同,所以在页面上显示的内容也不同。 - 物理分页和逻辑分页的联系与区别?
联系:都是根据页号将指定区间的数据发送到前台显示
区别:物理分页是在dao层SQL语句中查询到指定区间的数据,并将指定区间的数据发送给前端;逻辑分页在dao层SQL语句中查询到的是所有的信息,然后还需要通过Java代码获取到指定区间的数据发送给前端。
总结
以上就是对分页功能的记录。需要分清「逻辑分页」和「物理分页」联系和区别。逻辑分页SQL语句可能相对简单一点,但不适用于数据量极大的情况。数据量较大的时候,需要使用物理分页。重点理解分页工具类,然后结合我提供的思路和核心代码,基本上就可以实现分页功能了。
-
-
html+css实现简单分页页码效果
2015-04-19 17:59:37html+css实现简单分页页码效果源码,尚且没有复杂的后台,给前端新手学习之用 -
JAVA-分页查询
2022-03-28 15:01:45分页查询 分页查询将数据库中庞大的数据分段显示,每页显示用户自定义的行数,提高用户体验度,最主要的是如果一次性从服务器磁盘中读出全部数据到内存,有内存溢出的风险 真假分页 假分页: 其原理还是将所有的数据读到... -
【mysql】limit实现分页
2022-02-11 20:52:55分页 1. 使用limit实现数据的分页显示 需求1:每页显示20条记录,此时显示第1页 SELECT employee_id,last_name FROM employees LIMIT 0,20; 需求2:每页显示20条记录,此时显示第2页 SELECT employee_id,last_... -
java实现分页 jsp分页 分页
2011-05-12 09:27:23java实现分页 jsp分页 分页java实现分页 jsp分页 分页java实现分页 jsp分页 分页java实现分页 jsp分页 分页java实现分页 jsp分页 分页java实现分页 jsp分页 分页 -
打印分页,html强制分页
2012-09-25 00:18:51打印分页,html强制分页,一个表格一页,可以查看打印预览 -
MyBatis实现分页查询
2021-07-14 14:43:15MyBatis实现分页查询 -
pageHelper分页配置所需jar包
2016-09-08 11:49:54pageHelper分页配置所需jar包,可用 -
SpringBoot 查询redis 数据进行分页
2022-02-15 18:04:15查询redis 分页工具类 1.PageUtil package com.herdsric.admin.util; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.RedisTemplate; import org.... -
sql server 2008通用分页
2013-09-24 11:04:21SQL server2008中通用分页存储过程,表名,每页长度,页码都是动态赋值。 -
ES深度分页查询详解
2021-08-04 17:46:58ES分页查询详解 -
分页查询
2021-05-06 23:30:2201_分页查询概念 为什么要有分页查询 如果没有使用分页查询的话,存在两个问题: 浏览器的加载数据过多,容易导致浏览器崩溃 查询数据库的数据量过大,查询时间会非常长 分类 逻辑分页 一次性将所有数据... -
ElasticSearch-SpringBoot中三种分页查询总结
2022-04-03 17:06:50一、from+size 浅分页 DSL 查询方式 RestHighLevelClient 查询方式 二、scroll 深分页 DSL 查询方式 RestHighLevelClient 查询方式 三、search_after 深分页 DSL 查询方式 RestHighLevelClient 查询方式 一... -
Mybatis分页插件
2021-06-04 08:38:181、分页插件 MjBatis通过提供插件机制,让我们可以根据自己的需要去增强MyBats的功能。需要注意的是,如果没有完全理解lMy Batis的运行原理和插件的工作方式,最好不要使用插件,因为它会改变系底层的工作逻辑,给... -
【java】树形结构分页(真分页)
2022-04-26 13:30:08对于一个查询来说,如果数据量是不断增加的,并且对于最高权限要显示全表数据,就必须考虑真了,那么树形结构如何真分页分页呢?网上找了好多,并没有一个具体的方案,只能自己想一个了 真分页: 即每次只从数据库取... -
MyBatis-Plus 分页查询以及自定义sql分页
2021-02-22 17:57:50文章目录一、引言二、配置三、具体分页实现四、自定义sql分页查询五、多表sql分页查询 原博文,点击这里进行实现 一、引言 分页查询每个人程序猿几乎都使用过,但是有部分同学不懂什么是物理分页和逻辑分页。 物理... -
ASP.NET Repeater分页,查询分页
2011-07-23 11:22:36ASP.NET Repeater分页,查询分页 ASP.NET Repeater分页,查询分页 ASP.NET Repeater分页,查询分页 ASP.NET Repeater分页,查询分页 ASP.NET Repeater分页,查询分页