4、PageHelper分页查询
1、MyBatis的分页方式:
逻辑分页与物理分页
1、逻辑分页:使用MyBatis自带的RowBounds进行分页,是一次性查询很多数据,然后再在结果中检索分页的数据。这样做弊端是需要消耗大量的内存、有内存溢出的风险、对数据库压力较大。
2、物理分页:使用分页插件PageHelper或者自己写sql分页(limit),是从数据库查询指定条数的数据,弥补了一次性全部查出的所有数据的种种缺点,比如需要大量的内存,对数据库查询压力较大等问题。
2、PageHelper的原理:
PageHelper是MyBatis提供的分页插件;首先是在Mybatis里面配置了分页拦截器(PageInterceptor),即在执行相关Sql之前会拦截做一点事情;通过setLocalPage()方法,将分页信息保存在当前线程中。查询方法与之处于同一个线程中,共享ThreadLocal中的数据。selectlist查询之后赋值给的List list。这个list是Page 类型。再将list放到PageInfo<>中即可。
3、PageHelper分页实现:
(1)、建工程:
建立Springboost工程;
(2)、改POM:
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <!--SpringBoot框架web项目起步依赖--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.47</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid-spring-boot-starter</artifactId> <version>1.1.10</version> </dependency> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>1.3.0</version> </dependency> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> </dependency> <!--lombok插件--> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.16.18</version> <optional>true</optional> </dependency> <!--PageHelper插件--> <dependency> <groupId>com.github.pagehelper</groupId> <artifactId>pagehelper-spring-boot-starter</artifactId> <version>1.4.2</version> </dependency> </dependencies>
(3)、写YML:
server: port: 8081 spring: application: name: pagehelperdemo datasource: type: com.alibaba.druid.pool.DruidDataSource #当前数据源操作类型 driver-class-name: org.gjt.mm.mysql.Driver #mysql驱动包 url: jdbc:mysql://localhost:3306/demo?useUnicode=true&characterEncoding=utf-8&useSSL=false username: root password: 123456 druid: test-while-idle: false #关闭空闲检测 mybatis: mapperLocations: classpath:mapper/*.xml #resources下建mapper包
(4)、业务类:
//实现类 @Autowired private PageDemoMapper pageDemoMapper; /** * PageHelper分页查询 * @Param pageNum:页数 * @Param pageSize:每页显示的条目 * */ @Override public PageInfo<PageDemo> selectPage(Integer pageNum , Integer pageSize) { log.info("页数:"+pageNum); log.info("每页显示的条目:"+pageSize); //查询数据库的时候会自动加上limit //PageDemoMapper: List<PageDemo> selectAllDemo(); return PageHelper.startPage(pageNum, pageSize) .doSelectPageInfo(() -> pageDemoMapper.selectAllDemo()); }
4、自定义分页工具类:
import com.github.pagehelper.PageInfo; import org.springframework.util.ObjectUtils; import java.util.ArrayList; import java.util.List; public class PageHelperUtil { /** * @Description: @description: 自定义分页工具类 * @param pageNum 当前页 * @param pageSize 每页显示的数目 * @param list 总数据 */ public static <T> PageInfo<T> initPageInfo(int pageNum, int pageSize, List<T> list) { if(ObjectUtils.isEmpty(list)){ PageInfo<T> pageInfo = new PageInfo<>(new ArrayList<>()); // 当前页 pageInfo.setPageNum(pageNum); // 每页的数量 pageInfo.setPageSize(pageSize); return pageInfo; } int total = list.size(); // 默认如果当前页小于0则为第一页 pageNum = pageNum <= 0 ? 1 : pageNum; // 默认如果当前页大于最大的页数为当前页 pageNum = pageNum > (total + pageSize - 1) / pageSize ? (total + pageSize - 1) / pageSize : pageNum; // 将需要分页的数组进行截取处理 int fromIndex = 0; int toIndex = 0; if (total / pageSize == 0 && total % pageSize > 0) { // 表示当前数据只有一页 fromIndex = 0; toIndex = total; } else if (total / pageSize >= 1 && total % pageSize >= 0) { // 超过一页 fromIndex = (pageNum - 1) * pageSize; toIndex = pageNum * pageSize >= total ? total : pageSize * pageNum; } List<T> tempList = list.subList(fromIndex, toIndex);// 真正需要分页显示的数据 PageInfo<T> pageInfo = new PageInfo<>(tempList);// 结果集(每页显示的数据) pageInfo.setPageNum(pageNum);// 当前页 pageInfo.setPageSize(pageSize);// 每页的数量 pageInfo.setSize(tempList.size());// 当前页的数量 pageInfo.setStartRow(0);// 当前页面第一个元素在数据库中的行号 pageInfo.setEndRow(tempList.size() > 0 ? tempList.size() - 1 : 0);// 当前页面最后一个元素在数据库中的行号 pageInfo.setTotal(total);// 总记录数 pageInfo.setPages((total + pageSize - 1) / pageSize);// 总页数 calcNavigatepageNums(pageInfo);// 计算导航页 calcPage(pageInfo);// 计算前后页,第一页,最后一页 judgePageBoudary(pageInfo);// 判断页面边界 if (pageInfo.getList() == null) { pageInfo.setList(new ArrayList<>()); } return pageInfo; } /** * 计算导航页 */ private static <T> void calcNavigatepageNums(PageInfo<T> pageInfo) { int pages = pageInfo.getPages(); int navigatePages = pageInfo.getNavigatePages(); int pageNum = pageInfo.getPageNum(); // 当总页数小于或等于导航页码数时 if (pages <= navigatePages) { pageInfo.setNavigatepageNums(new int[pages]); for (int i = 0; i < pages; i++) { pageInfo.getNavigatepageNums()[i] = i + 1; } } else { // 当总页数大于导航页码数时 pageInfo.setNavigatepageNums(new int[navigatePages]); int startNum = pageNum - navigatePages / 2; int endNum = pageNum + navigatePages / 2; if (startNum < 1) { startNum = 1; // (最前navigatePages页 for (int i = 0; i < navigatePages; i++) { pageInfo.getNavigatepageNums()[i] = startNum++; } } else if (endNum > pages) { endNum = pages; // 最后navigatePages页 for (int i = navigatePages - 1; i >= 0; i--) { pageInfo.getNavigatepageNums()[i] = endNum--; } } else { // 所有中间页 for (int i = 0; i < navigatePages; i++) { pageInfo.getNavigatepageNums()[i] = startNum++; } } } } /** * 计算前后页,第一页,最后一页 */ private static <T> void calcPage(PageInfo<T> pageInfo) { int[] navigatepageNums = pageInfo.getNavigatepageNums(); int pageNum = pageInfo.getPageNum(); int pages = pageInfo.getPages(); if (navigatepageNums != null && navigatepageNums.length > 0) { pageInfo.setFirstPage(navigatepageNums[0]); pageInfo.setLastPage(navigatepageNums[navigatepageNums.length - 1]); if (pageNum > 1) { pageInfo.setPrePage(pageNum - 1); } if (pageNum < pages) { pageInfo.setNextPage(pageNum + 1); } } } /** * 判定页面边界 */ private static <T> void judgePageBoudary(PageInfo<T> pageInfo) { int pageNum = pageInfo.getPageNum(); int pages = pageInfo.getPages(); pageInfo.setIsFirstPage(pageNum == 1); pageInfo.setIsLastPage(pageNum == pages); pageInfo.setHasPreviousPage(pageNum > 1); pageInfo.setHasNextPage(pageNum < pages); } }