Mybatis分页框架-PageHelper
- 一、PageHelper基础使用
- 1.引入jar包
- 2.配置conifg
- 3.测试使用
- 二、PageHelper的多种用法
- 1.使用PageHelper.startPage传入对象
- 2.不使用PageHelper.startPage,而使用PageHelper.offsetPage
- 3.使用Lambda进行分页
- 4.不使用PageHelper直接分页
- 5.想要使用分页接口查询全部数据
- 6.输入异常页码,也支持分页
这篇文章用以总结PageHelper分页插件的使用,PageHelper是Mybatis的分页插件,他的实现原理是基于Mybatis的拦截器QueryInterceptor 来实现的,通过拦截sql查询,来对sql进行增强改造,其实这种思想比比皆是。比如MP的分页插件也是这种思想,比如各种组件里的Interceptor也都是这种思想。这里总结下常用的用法。
一、PageHelper基础使用
java里常用的分页组件都是物理分页,基本没有逻辑分页。PageHelper也是物理分页插件。物理分页就是使用sql直接对数据进行分页处理,逻辑分页时数据全部查出来,然后再进行分页,这样再数据量大时,内容根本扛不住(除非系统比较小)。所以真正使用时都是使用PageHelper这种物理分页插件
1.引入jar包
没啥好说的,使用maven进行引入jar包,官方文档推荐使用最新版jar包,这里可以通过官网看看最新版是多少,如下图:
文章写作时间:2023-09-22
PageHelper最新版本:5.3.3
官网地址: PageHelper官网
本文使用Springboot版本:2.4.4
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>5.3.3</version>
<!-- 分页插件只会在编译期有用,这里可以声明为compile -->
<scope>compile</scope>
</dependency>
2.配置conifg
使用PageHelper必须配置他的分页拦截器PageInterceptor,这个分页拦截器正是使用PageHelper实现分页的关键。最主要的一点是需要我们指定数据库的方言(通俗说就是数据库的类型),因为不同数据库的分页实现是不同的,所以我们需要指明数据库这样PageHelper才可以帮助我们进行动态调整SQL。他具有以下配置项。
注意:如果不配置这个官方文档说也可以自己识别数据库方言,但笔者不配置时发现分页无法生效,验证了5.3.3 和 5.1.11 两个版本都是无法正常分页的,所以还是加上这个配置最好
import com.github.pagehelper.PageInterceptor;
import org.apache.ibatis.session.SqlSessionFactory;
import org.springframework.context.annotation.Configuration;
import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.util.List;
import java.util.Properties;
/**
* @author pcc
* 这是分页插件PageHelper的配置信息
* 使用PageHelper的原因是MP的分页对于多表分页查询和自定义查询的分页支持不够优秀
*/
@Configuration
public class PageHelperConfig {
/**
* 可能存在多个连接工厂,是允许这么注入的
*/
@Resource
private List<SqlSessionFactory> sqlSessionFactoryList;
@PostConstruct
public void initConfig(){
PageInterceptor pageInterceptor = new PageInterceptor();
Properties properties = new Properties();
// 设置数据源方言,使用mysql
properties.setProperty("helperDialect","mysql");
pageInterceptor.setProperties(properties);
sqlSessionFactoryList.forEach(factory ->factory.getConfiguration().addInterceptor(pageInterceptor));
}
}
以上就完成了所有配置了,其实非常简单易用。
3.测试使用
使用其实也很简单,不过需要注意以下两点:
-
- 只有紧跟在PageHelper.startPage方法后的第一个Mybatis的查询(Select)方法会被分页。
-
- 不支持带有for update语句的分页
-
- 使用下面这种分页方式,查询方法返回结果必须是List<T>,因为PageHelper分页返回的对象是ArrayList类型的Page
下面是分页的代码:
/**
* 使用 PageHelper进行分页
* @param tbTaskItemsVO 入参
* @return 返回
*/
@PostMapping("/getTaskItemsPage2")
public PageInfo<TbTaskItems> getTaskItems2(TbTaskItemsVO tbTaskItemsVO){
PageHelper.startPage(tbTaskItemsVO.getPageNum(),tbTaskItemsVO.getPageSize());
List<TbTaskItems> itemsList = iTbTaskItemsService.queryItems();
PageInfo<TbTaskItems> pageInfo = new PageInfo<>(itemsList);
return pageInfo;
}
上面代码就可以正常实现分页了:
可以看到我们分页的关键信息都是正确的了,使用起来很简单,不过还是有几点需要说明下:
- 1.PageHelper.startPage 传入的是pageNum,pageSize
- 2.查询方法(这里是iTbTaskItemsService.queryItems)返回类型必须是ArrayList<T>或他的父类,这里虽然是使用List接收的返回值,看着和原方法没有区别,其实这里的iTbTaskItemsService.queryItems返回参数其实是Page,因为Page是ArrayList的子类所以可以这么写,所以我们方法定义时需要定义返回类型是ArrayList或者他的父类。
二、PageHelper的多种用法
实际工作场景中基本都是使用第一节中的用法就完全足够了,这里做下扩展,说下PageHelper的其他常用写法。下面前几种是比较常用的写法,除了这几种以外还可以支持传入RowBound,或者写查询方法声明分页参数,不过这两种不常用就不说了,感兴趣可以看官方文档:
PageHelper官方文档
1.使用PageHelper.startPage传入对象
这里使用和第一种区别不大,传入对象是第一种的重载方法,传入的对象就一个要求必须有pageNum、pageSize两个参数,且不能为空,这样也可以正常分页。
// 对于上面的写法就动如下代码即可:
PageHelper.startPage(tbTaskItemsVO);
2.不使用PageHelper.startPage,而使用PageHelper.offsetPage
这种写法和上面PageHelper.startPage(offSet,limit)的意义是从offSet的下标开始取数,取limit条数据,这种分页还得我们计算,比第一种稍微麻烦一些。
PageHelper.startPage(pageNum*PageSize,PageSize);
3.使用Lambda进行分页
PageHelper还支持Java8的lambda的写法,只要支持Java8肯定也支持匿名内部类的写法,这里就只展示Java8的写法了,Java7没有什么区别了
/**
* 使用 PageHelper进行分页
* @param tbTaskItemsVO 入参
* @return 返回
*/
@PostMapping("/getTaskItemsPage2")
public PageInfo<TbTaskItems> getTaskItems2(TbTaskItemsVO tbTaskItemsVO){
PageInfo<TbTaskItems> objectPageInfo = PageHelper.startPage(tbTaskItemsVO).doSelectPageInfo(() -> {
iTbTaskItemsService.queryItems();
});
return objectPageInfo;
}
4.不使用PageHelper直接分页
这种写法需要增加一个PageInterceptor的配置项,才可以支持,默认是不支持的,这种写法最简单,会让写代码的看不到分页的任何痕迹,但是这样反而不好,容易让人忽略,但是这种写法最简洁。
- 1.新增配置项
// 配置supportMethodsArguments=true
// 分页插件会从查询方法的参数值中寻找pageNum,pageSize进行分页,找到就可以进行分页
import com.github.pagehelper.PageInterceptor;
import org.apache.ibatis.session.SqlSessionFactory;
import org.springframework.context.annotation.Configuration;
import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.util.List;
import java.util.Properties;
/**
* @author pcc
* 这是分页插件PageHelper的配置信息
* 使用PageHelper的原因是MP的分页对于多表分页查询和自定义查询的分页支持不够优秀
*/
@Configuration
public class PageHelperConfig {
/**
* 可能存在多个连接工厂,是允许这么注入的
*/
@Resource
private List<SqlSessionFactory> sqlSessionFactoryList;
@PostConstruct
public void initConfig(){
PageInterceptor pageInterceptor = new PageInterceptor();
Properties properties = new Properties();
// 设置数据源方言,使用mysql
properties.setProperty("helperDialect","mysql");
// 支持自动分页,需要保证查询方法的对象中必须含有pageNum,pageSize
properties.setProperty("supportMethodsArguments","true");
pageInterceptor.setProperties(properties);
sqlSessionFactoryList.forEach(factory ->factory.getConfiguration().addInterceptor(pageInterceptor));
}
}
- 2.查询方法需要修改为传递对象或者Map也是可以的,不过都必须含有pageNum,pageSize才可以。
/**
* 使用 PageHelper进行分页
* @param tbTaskItemsVO 入参
* @return 返回
*/
@PostMapping("/getTaskItemsPage2")
public PageInfo<TbTaskItems> getTaskItems2(TbTaskItemsVO tbTaskItemsVO){
List<TbTaskItems> itemsList = iTbTaskItemsService.queryItems(tbTaskItemsVO);
PageInfo<TbTaskItems> pageInfo = new PageInfo<>(itemsList);
return pageInfo;
}
5.想要使用分页接口查询全部数据
需要新增一个配置参数:pageSizeZero=true,配置这个参数后如果想要查询全部数据,只需要传递pageSize=0,就会默认查询全部数据,不过返回的还是Page信息。
// 只展示配置信息
public void initConfig(){
PageInterceptor pageInterceptor = new PageInterceptor();
Properties properties = new Properties();
// 设置数据源方言,使用mysql
properties.setProperty("helperDialect","mysql");
// 支持自动分页,需要保证查询方法的对象中必须含有pageNum,pageSize
properties.setProperty("supportMethodsArguments","true");
// 支持查询全部信息
properties.setProperty("pageSizeZero","true");
pageInterceptor.setProperties(properties);
sqlSessionFactoryList.forEach(factory ->factory.getConfiguration().addInterceptor(pageInterceptor));
}
其他使用则没有区别了,就不重复举例了
6.输入异常页码,也支持分页
当输入异常页码也可以支持进行分页,需要增加配置:reasonable=true,当增加这个配置后,当pageNum<=0时,会查询第一页,pageNum>最大页,会查询最后一页。当然pageSize必须有值。
// 只展示配置信息
public void initConfig(){
PageInterceptor pageInterceptor = new PageInterceptor();
Properties properties = new Properties();
// 设置数据源方言,使用mysql
properties.setProperty("helperDialect","mysql");
// 支持自动分页,需要保证查询方法的对象中必须含有pageNum,pageSize
properties.setProperty("supportMethodsArguments","true");
// 支持查询全部信息
properties.setProperty("pageSizeZero","true");
// 支持异常页码查询
properties.setProperty("reasonable","true");
pageInterceptor.setProperties(properties);
sqlSessionFactoryList.forEach(factory ->factory.getConfiguration().addInterceptor(pageInterceptor));
}