PageHelper 参数合理化的坑

447 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第 6天,点击查看活动详情

1 前言

数据分页是在软件系统中必备的功能,在使用 mybatis 框架时, PageHelper 是后台分页中最常用的一个。 PageHelper 是 Mybatis 的一个插件,内部实现了一个 PageInterceptor 拦截器,其中也使用到了 ThreadLocal 来实现参数的传递和获取。在本文中将会介绍 PageHelper 实现分页的关键步骤,并列举一些常见的坑和解决方法。

2 PageHelper 的使用方法

在项目中使用 PageHelper 非常简单,只需要引入依赖即可:

<dependency>
    <groupId>com.github.pagehelper</groupId>
    <artifactId>pagehelper</artifactId>
    <version>5.2.1</version>
</dependency>

在代码中,具体的使用方法如下:

# 起始页和每页的数据量
PageHelper.startPage(1,10);
# 查询数据
List<Config> configs = configMapper.selectList(new QueryWrapper<>());
# 将数据进行包装,返回分页对象
PageInfo<Config> of = PageInfo.of(configs);

3 分页原理

PageHelper 在分页时,会将分页所需要的参数 PageHelper.startPage 存储到当前线程的上下文中,然后利用 PageInterceptor 这个分页拦截器拦截,从 ThreadLocal 拿到分页信息,最后再将线程上下文 ThreadLocal 中的信息清除掉。

因此在整个过程中,分页 startPage 需要在执行查询的方法之前,而且查询语句和分页语句不能在两个线程中,否则会导致分页参数传递失败,从而导致数据查询错误。

设置 startPage 时的源码内容,可以看到最终调用了 setLocalPage 的方法 再继续往下走会看到,将 page 参数存放到线程上下文中。

在 mybatis 中,我们都知道 SqlSessionFactoryBuilder 的方法,这个方法会解析所有的配置文件,通过 pluginElement 加载所有的插件,在需要分页的时候,先查询总页数然后再查询当前分页数据。

在进行分页查询时,会遇到这样的情况,如果数据有10条,查询第二页,每页10条数据时,第二页的数据依然是第一页的数据,这就是很诡异的事件,通过分析我们知道在设置总页数,会有一个 reasonable 的参数,即参数合理化,当开启该项参数时,如果当前查询页大于总页数时,则当前页为最后一页,这就是参数合理化的意义,但是在实际的业务中,有时候并不需要这样的配置,所以需要配置 reasonable = false 即可,默认改参数为 true。

pagehelper 的其它参数如下所示:

pagehelper:
  helperDialect: mysql #检测适配当前的数据库类型
  reasonable: false # 设置为true时,当前页数<=0时,会自动从1开
  supportMethodsArguments: true #支持通过函数参数进行分页
  params: count=countSql #

4 总结

在本文中主要介绍了 pagehelper 的使用方法,以及插件的实现原理,最后介绍了其配置参数 reasonable ,避免出现查询大于总页数时,实际查询最后一页数据而不是空数据的情况。