Skip to content

MyBatis-Flex分页扩展

1197字约4分钟

2023-12-06

MyBatis filex 分页查询官网API如下

在 MyBatis-Flex 的 BaseMapper 中,提供了如下的分页查询功能:

  • paginate(pageNumber, pageSize, queryWrapper):分页查询。
  • paginateWithRelations(pageNumber, pageSize, queryWrapper):分页查询,及其 Relation 字段内容。
  • paginate(pageNumber, pageSize, whereConditions):分页查询。
  • paginateWithRelations(pageNumber, pageSize, whereConditions):分页查询,及其 Relation 字段内容。
  • paginate(pageNumber, pageSize, totalRow, queryWrapper):分页查询。
  • paginateWithRelations(pageNumber, pageSize, totalRow, queryWrapper):分页查询,及其 Relation 字段内容。
  • paginate(pageNumber, pageSize, totalRow, whereConditions):分页查询。
  • paginateWithRelations(pageNumber, pageSize, totalRow, whereConditions):分页查询,及其 Relation 字段内容。
  • paginate(page, queryWrapper):分页查询。
  • paginate(page, queryWrapper, consumers):分页查询。
  • paginateWithRelations(page, queryWrapper):分页查询,及其 Relation 字段内容。
  • paginateWithRelations(page, queryWrapper, consumers):分页查询,及其 Relation 字段内容。
  • paginateAs(pageNumber, pageSize, queryWrapper, asType):分页查询。
  • paginateAs(pageNumber, pageSize, totalRow, queryWrapper, asType):分页查询。
  • paginateAs(page, queryWrapper, asType):分页查询。
  • paginateAs(page, queryWrapper, asType, consumers):分页查询。
  • paginateWithRelationsAs(pageNumber, pageSize, queryWrapper, asType):分页查询,及其 Relation 字段内容。
  • paginateWithRelationsAs(pageNumber, pageSize, totalRow, queryWrapper, asType):分页查询,及其 Relation 字段内容。
  • paginateWithRelationsAs(page, queryWrapper, asType):分页查询,及其 Relation 字段内容。
  • paginateWithRelationsAs(page, queryWrapper, asType, consumers):分页查询,及其 Relation 字段内容。

参数说明:

  • pageNumber: 当前页码,从 1 开始
  • pageSize: 每 1 页的数据量
  • totalRow: 非必须值,若传入该值,mybatis-flex 则不再去查询总数据量(若传入小于 0 的数值,也会去查询总量)。
  • queryWrapper: 查询条件
  • queryCondition: 查询条件

采用MyBatis flex实现分页存在局限性,复杂逻辑多张表关联查询时使用flex的api不是很好,因此我们需要自己通过xml实现自定义SQL查询,但是查询时除了查询list数据,还需要进行分页count统计,需要编写2个SQL组合,非常麻烦!因此我们采用flex整合PageHelper插件实现分页。

MyBaits PageHelper 分页插件官网

pagehelper

1. 普通项目添加maven依赖

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

2. 使用 Spring Boot 时

<dependency>
    <groupId>com.github.pagehelper</groupId>
    <artifactId>pagehelper-spring-boot-starter</artifactId>
    <version>最新版本</version>
</dependency>

3. 配置拦截器插件

1).在 MyBatis 配置 xml 中配置拦截器插件

<!--
    plugins在配置文件中的位置必须符合要求,否则会报错,顺序如下:
    properties?, settings?,
    typeAliases?, typeHandlers?,
    objectFactory?,objectWrapperFactory?,
    plugins?,
    environments?, databaseIdProvider?, mappers?
-->
<plugins>
    <!-- com.github.pagehelper为PageHelper类所在包名 -->
    <plugin interceptor="com.github.pagehelper.PageInterceptor">
        <!-- 使用下面的方式配置参数,后面会有所有的参数介绍 -->
        <property name="param1" value="value1"/>
    </plugin>
</plugins>

2).在 Spring 配置文件中配置拦截器插件

<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
  <!-- 注意其他配置 -->
  <property name="plugins">
    <array>
      <bean class="com.github.pagehelper.PageInterceptor">
          <property name="properties">
              <!--使用下面的方式配置参数,一行配置一个 -->
              <value>
                  params=value1
              </value>
          </property>
      </bean>
    </array>
  </property>
</bean>

3). 在 Spring Boot 中配置

Spring Boot 引入 starter 后自动生效,对分页插件进行配置时,在 Spring Boot 对应的配置文件 application.[properties|yaml] 中配置。

MyBatis Flex集成PageHelper

MyBaits Flex是在mybatis框架基础上进行的增强,在springboot项目中使用pagehelper-spring-boot-starter自动装配后会导致mybatis flex查询异常,执行sql时参数无法正常填充到预处理sql中。打开PageHelper starter的pom如下:

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter</artifactId>
    </dependency>
    <dependency>
        <groupId>org.mybatis.spring.boot</groupId>
        <artifactId>mybatis-spring-boot-starter</artifactId>
    </dependency>
    <dependency>
        <groupId>com.github.pagehelper</groupId>
        <artifactId>pagehelper-spring-boot-autoconfigure</artifactId>
    </dependency>
    <dependency>
        <groupId>com.github.pagehelper</groupId>
        <artifactId>pagehelper</artifactId>
    </dependency>
</dependencies>

PageHelper starter依赖了mybatis starter和PageHelper,PageHelper是分页的实现包,pagehelper autoconfigure是基于springbooot 的自动装配包。问题就出在此包上。我们打开源码查看

@Configuration
@ConditionalOnBean({SqlSessionFactory.class})
@EnableConfigurationProperties({PageHelperProperties.class})
@AutoConfigureAfter({MybatisAutoConfiguration.class})
@Lazy(false)
public class PageHelperAutoConfiguration implements InitializingBean {
    private final List<SqlSessionFactory> sqlSessionFactoryList;
    private final PageHelperProperties properties;

    public PageHelperAutoConfiguration(List<SqlSessionFactory> sqlSessionFactoryList, PageHelperProperties properties) {
        this.sqlSessionFactoryList = sqlSessionFactoryList;
        this.properties = properties;
    }

    public void afterPropertiesSet() throws Exception {
        PageInterceptor interceptor = new PageInterceptor();
        interceptor.setProperties(this.properties);
        Iterator var2 = this.sqlSessionFactoryList.iterator();

        while(var2.hasNext()) {
            SqlSessionFactory sqlSessionFactory = (SqlSessionFactory)var2.next();
            org.apache.ibatis.session.Configuration configuration = sqlSessionFactory.getConfiguration();
            if (!this.containsInterceptor(configuration, interceptor)) {
                configuration.addInterceptor(interceptor);
            }
        }

    }

    private boolean containsInterceptor(org.apache.ibatis.session.Configuration configuration, Interceptor interceptor) {
        try {
            return configuration.getInterceptors().contains(interceptor);
        } catch (Exception var4) {
            return false;
        }
    }
}

注意:@AutoConfigureAfter({MybatisAutoConfiguration.class}) 这里,mybatis flex也是在MybatisAutoConfiguration之后初始化的,这就导致mybatis flex和PageHelper出现问题。我们改造也很简单,只需要让PageHelper在mybatis flex初始化完毕后再注册PageInterceptor。因此PageHelper autoconfigure我们需要自己实现。具体方法如下:

1). 删除POM中的依赖

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

2).自己实现config,改动就一句,让PageHelper插件注册在mybatis flex 配置完毕后执行。

@Configuration
@AutoConfigureAfter(MybatisFlexAutoConfiguration.class)
public class PageHelperConfig implements InitializingBean {

    @Autowired
    private List<SqlSessionFactory> sqlSessionFactoryList;

    @Override
    public void afterPropertiesSet() throws Exception {
        PageInterceptor interceptor = new PageInterceptor();
        Properties props = new Properties();
        props.setProperty("helperDialect", "mysql");
        interceptor.setProperties(props);
        for (SqlSessionFactory sqlSessionFactory : sqlSessionFactoryList) {
            org.apache.ibatis.session.Configuration configuration = sqlSessionFactory.getConfiguration();
            if (!containsInterceptor(configuration, interceptor)) {
                configuration.addInterceptor(interceptor);
            }
        }
    }

    /**
     * 是否已经存在相同的拦截器
     *
     * @param configuration
     * @param interceptor
     * @return
     */
    private boolean containsInterceptor(org.apache.ibatis.session.Configuration configuration, Interceptor interceptor) {
        try {
            return configuration.getInterceptors().stream().anyMatch(config->interceptor.getClass().isAssignableFrom(config.getClass()));
        } catch (Exception e) {
            return false;
        }
    }
}