springboot3整合pageHelper实现分页功能

1、介绍:

PageHelper是一个开源的Java分页插件,它提供了方便的分页查询功能,适用于大多数基于Java的持久层框架(如MyBatis、Hibernate等)。

官网:MyBatis 分页插件 PageHelper

在一个程序中难免会使用到查询操作,在查询操作中如果数据量太大则需要进行分页查询,分页操作的实现方法有很多,比如:在 mybatis 中 xml 文件中通过 limit 关键字进行分页查询,该插件就是为了简化在 xml 中进行分页操作的工具;好比在 Mybatis-Plus 中也对分页操作进行了封装,通过调用 selectPage() 方法就可以实现分页操作。

 在 sql 中使用 limit 进行分页查询

SELECT * FROM user LIMIT 10, 10
  • offset 是相对于首行的偏移量(首行是 0),rows 是返回条数
  • mapper 中可以传变量,即在实际使用的时候 offset 与 rows 可以用变量替代

我们当然可以在sql中进行分页,但是为了简化代码。我们还是会使用一些插件来帮我们更好的进行分页操作。如:在项目中我们执行一个分页查询时,很多时候还需要知道该查询的其他信息,比如:总数、每页数量、当前页数、是否有上一页或者是否有下一页等等,这些信息如果每次都自己写的话就会太繁琐冗余了,而 PageHelper 插件能够帮助我们更加方便地获取这些信息,大大方便了我们的开发效率。

我始终认为官网才是一个技术最权威、最公正的对照。如果你在使用某个相应的技术中出现了错误,那么一定要先去官网上查找原因。现在的web开发使用到的框架大多为spring boot,所以本篇文章只是教会你如何快速的在spring boot项目中使用pageHelper分页插件,并介绍一些一些常用的方法,如果你有其他的疑问,可以在官网中查找。

2、新建spring boot项目,并导入依赖

引入pageHelper的坐标(我引入的使pageHelper整合spring boot的依赖)

   <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>3.0.1</version>
        </dependency>

        <dependency>
            <groupId>com.github.pagehelper</groupId>
            <artifactId>pagehelper-spring-boot-starter</artifactId>
            <version>1.4.7</version>
        </dependency>

在yml配置文件中对pageHelper进行一些配置,能更好的使用这个插件;

# PageHelper 分页插件配置
pagehelper:
  helper-dialect: mysql
  reasonable: true
  support-methods-arguments: true
  params: count=countsql

helper-dialect:指定数据库,不指定的话会默认自动检测数据库类型
reasonable:是否启动分页合理化。如果启用,当 pagenum < 1 时,会自动查询第一页的数据,当 pagenum > pges 时,自动查询最后一页数据;不启用的,以上两种情况都会返回空数据,如果启用则 pageHelper可以自动拦截请求参数中的 pageNum,pageSize参数,否则需要使用 PageHelper.startPage(pageNum,pageSize) 方法调用。
support-methods-arguments:默认为 false,分页插件会从查询方法的参数值中,自动根据上面 params 配置的字段中取值,查找到合适的值时就会自动分页。
params:用于从对象中根据属性名取值,可以配置 pageNum,pageSize,count,pageSizeZero,reasonable,不配置映射的用默认值,默认值为 pageNum=pageNum;pageSize=pageSize;count=countSql;reasonable=reasonable;pageSizeZero=pageSizeZero

创建一个mapper接口:

public interface UsersMapper   {
//查询所有
    List<Users> getAll();
}

mybatis的配置文件:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration PUBLIC
        "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <settings>
        <!-- 设置驼峰标识 -->
        <setting name="mapUnderscoreToCamelCase" value="true"/>
        <!-- 打印SQL语句 -->
        <setting name="logImpl" value="STDOUT_LOGGING"/>
    </settings>

<!--    <plugins>-->
<!--        &lt;!&ndash; 分页插件 &ndash;&gt;-->
<!--        <plugin interceptor="com.github.pagehelper.PageInterceptor"/>-->
<!--    </plugins>-->

    <mappers>
    <package name="com.zq.pagehelpdemo.mapper"/>
    </mappers>

</configuration>






我们已经引入了pagehelper-spring-boot-starter的依赖。所以pageHelper插件在项目启动时会自动注入到容器中。如果你的项目不是spring boot项目或者引入的依赖不是pageHelper整合了spring boot的依赖,那么就需要在mybatis的配置文件中引入pageHelper的插件。

在项目中使用pageHelper实现分页:

  @Override
    public List<Users> getPage(int page, int size) {
//获取第page页,size条内容,默认查询总数count
        PageHelper.startPage(page,size);
        
//分页时,实际返回的结果list类型是Page<E>,如果想取出分页信息,需要强制转换为Page<E>,
        return getAll();
    }

xml中的sql语句:
 

 <select id="getAll" resultType="com.zq.pagehelpdemo.entity.Users">

select * from users

    </select>

运行结果:
在启动项目时看到这个图标就说明pageHelper注入成功了:

sql语句:

可以看到先执行了一个查询所有记录的语句,然后执行了我们在xml中写的查询语句,在查询语句的最后加上了LIMIT字段。

其实这些sql都不是我们写的,我们只不过是写了一个

    PageHelper.startPage(page,size);

这一条语句就会帮助我们自动生成分页语句;

注意PageHelper.startPage方法使用也有限制:

PageHelper.startPage方法重要提示

只有紧跟在PageHelper.startPage方法后的第一个Mybatis的查询(Select)方法会被分页。(PageHelper 启动了一个新的线程)

还有在使用pageHelper插件时的几个重要提示:

请不要配置多个分页插件

请不要在系统中配置多个分页插件(使用Spring时,mybatis-config.xmlSpring<bean>配置方式,请选择其中一种,不要同时配置多个分页插件)!

分页插件不支持带有for update语句的分页

对于带有for update的sql,会抛出运行时异常,对于这样的sql建议手动分页,毕竟这样的sql需要重视。

分页插件不支持嵌套结果映射

由于嵌套结果方式会导致结果集被折叠,因此分页查询的结果在折叠后总数会减少,所以无法保证分页结果数量正确。

pageHelper使用时,要注意线程的安全性,避免重复调用分页参数:

PageHelper 方法使用了静态的 ThreadLocal 参数,分页参数和线程是绑定的。

只要你可以保证在 PageHelper 方法调用后紧跟 MyBatis 查询方法,这就是安全的。因为 PageHelper 在 finally 代码段中自动清除了 ThreadLocal 存储的对象。

如果代码在进入 Executor 前发生异常,就会导致线程不可用,这属于人为的 Bug(例如接口方法和 XML 中的不匹配,导致找不到 MappedStatement 时), 这种情况由于线程不可用,也不会导致 ThreadLocal 参数被错误的使用。

下面有一段代码示例:
 

    public List<Users> getPages(int page, int size) {
//        调用PageHelper的静态方法startPage
        PageHelper.startPage(page, size);
        List<Users> usersList=new ArrayList<>();
        if (false) {
            System.out.println("调用了查询方法");
          usersList  = usersMapper.getAll();
        } else {
            System.out.println("没有调用了查询方法");
        }
return usersList;
    }

在这个方法中,我调用了PageHelper.startPage方法,这时就会导致PageHelper生产了一个分页参数,但是没有被消费,这个参数就会一直保留在这个线程上。当这个线程再次被使用时,就可能导致可能不该分页的方法去消费这个分页参数,这就产生了莫名其妙的分页。

所以我们一定要保证PageHelper.startPage方法后面跟了一个查询方法。最好的情况就是将这两条语句就放在一起,前后挨着。

当然,使用 PageHelper.startPage进行分页时基本的用法。如果你不仅仅想要得到分页内容,还要得到一些分页具体的值,如查询的总记录数等等。可以使用PageInfo,在这个对象中pageHelper封装了我们对于分页来说的所有参数,可以满足我们对于分页操作的所有需求。

public class PageInfo<T> extends PageSerializable<T> {
    public static final int DEFAULT_NAVIGATE_PAGES = 8;
    // 当前页
    private int pageNum;
    // 每页的数量
    private int pageSize;
    // 当前页的数量
    private int size;
    // 下面两个不常用
    // 在页面中“显示 startRow” 到 endRow 共 size条数据
    // 当前页面中第一个元素的在数据库中的行号
    private long startRow;
    // 当前页面最后一个元素在数据库中的行号
    private long endRow;
    // 总页数
    private int pages;
    // 前一页
    private int prePage;
    // 下一页
    private int nextPage;
    // 是否为第一页
    private boolean isFirstPage;
    // 是否为最后一页
    private boolean isLastPage;
    // 是否有前一页
    private boolean hasPreviousPage;
    // 是否有下一页
    private boolean hasNextPage;
    // 导航页码数
    private int navigatePages;
    // 所有导航页号
    private int[] navigatepageNums;
    // 导航条上的第一页
    private int navigateFirstPage;
    // 导航条上的最后一页
    private int navigateLastPage;
    ......
}

在代码中使用PageInfo:

(在创建PageInfo时,指定泛型。并将查询到的结果作为入参传递)

    @Override
    public PageInfo<Users> getPageInfo(int page, int size) {
        PageHelper.startPage(page,size);


        List<Users> usersList = getAll();
//        将查询到的数据封装到PageInfo中
        PageInfo<Users> pageInfo=new PageInfo<>(usersList);
        
        return pageInfo;
    }

运行结果为:

可以很清晰的看到输出了PageInfo的所有属性,我们可以根据我们的需求动态的获取用到的参数。

  • 24
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

张乔24

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值