Mybatis分页框架-PageHelper


这篇文章用以总结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.测试使用

使用其实也很简单,不过需要注意以下两点:

    1. 只有紧跟在PageHelper.startPage方法后的第一个Mybatis的查询(Select)方法会被分页。
    1. 不支持带有for update语句的分页
    1. 使用下面这种分页方式,查询方法返回结果必须是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));
    }

猜你喜欢

转载自blog.csdn.net/m0_46897923/article/details/133188854
今日推荐