SpringBoot中如何实现Mybatis分页

1. 每次查询sql使用limit offset

但是该方法有个弊端,当需要把所有查询记录数返回给前端时,需要查询一次count(*),比较浪费时间,下面来重点讲Mybatis中分页插件的实现。

2. 使用PageHelper插件

首先导入maven依赖:

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

spring boot需要在application.yml加入配置

pagehelper:
  helper-dialect: mysql
  reasonable: true
  support-methods-arguments: true
  params: count=countSql

接下来就可以使用分页了(以下内容源于官方文档):

PageHelper.startPage静态方法调用启用分页

除了 PageHelper.startPage 方法外,还提供了类似用法的 PageHelper.offsetPage 方法。

在你需要进行分页的 MyBatis 查询方法前调用 PageHelper.startPage 静态方法即可,紧跟在这个方法后的第一个MyBatis 查询方法会被进行分页。

例一:

//request: url?pageNum=1&pageSize=10
//支持 ServletRequest,Map,POJO 对象,需要配合 params 参数
PageHelper.startPage(request);
//紧跟着的第一个select方法会被分页
List<Country> list = countryMapper.selectIf(1);//Mybatis select方法

//后面的不会被分页,除非再次调用PageHelper.startPage
List<Country> list2 = countryMapper.selectIf(null);
//list1
assertEquals(2, list.get(0).getId());
assertEquals(10, list.size());
//分页时,实际返回的结果list类型是Page<E>,如果想取出分页信息,需要强制转换为Page<E>,
//或者使用PageInfo类(下面的例子有介绍)
assertEquals(182, ((Page) list).getTotal());
//list2
assertEquals(1, list2.get(0).getId());
assertEquals(182, list2.size());

如注解所说,要取出分页信息,需要强制转换。Page是List子类,要使用Page子类中特有方法需要强制向下转型获取特有方法。

例二:使用PageInfo的用法:

//获取第1页,10条内容,默认查询总数count
PageHelper.startPage(1, 10);
List<Country> list = countryMapper.selectAll();
//用PageInfo对结果进行包装
PageInfo page = new PageInfo(list);
//测试PageInfo全部属性
//PageInfo包含了非常全面的分页属性
assertEquals(1, page.getPageNum());
assertEquals(10, page.getPageSize());
assertEquals(1, page.getStartRow());
assertEquals(10, page.getEndRow());
assertEquals(183, page.getTotal());
assertEquals(19, page.getPages());
assertEquals(1, page.getFirstPage());
assertEquals(8, page.getLastPage());
assertEquals(true, page.isFirstPage());
assertEquals(false, page.isLastPage());
assertEquals(false, page.isHasPreviousPage());
assertEquals(true, page.isHasNextPage());

PageHelper 安全调用

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

如果你写出下面这样的代码,就是不安全的用法:

PageHelper.startPage(1, 10);
List<Country> list;
if(param1 != null){
    list = countryMapper.selectIf(param1);
} else {
    list = new ArrayList<Country>();
}

这种情况下由于 param1 存在 null 的情况,就会导致 PageHelper 生产了一个分页参数,但是没有被消费,这个参数就会一直保留在这个线程上。当这个线程再次被使用时,就可能导致不该分页的方法去消费这个分页参数,这就产生了莫名其妙的分页。

上面这个代码,应该写成下面这个样子:

List<Country> list;
if(param1 != null){
    PageHelper.startPage(1, 10);
    list = countryMapper.selectIf(param1);
} else {
    list = new ArrayList<Country>();
}

这种写法就能保证安全。