美文网首页
PageHelper 代码中的调用!

PageHelper 代码中的调用!

作者: SevenCoder | 来源:发表于2021-04-17 20:38 被阅读0次

    上一篇文件已经介绍PageHelper 集成 springboot !

    分页插件支持以下几种调用方式:

    //第一种,RowBounds方式的调用

    List<Country> list = sqlSession.selectList("x.y.selectIf", null, new RowBounds(0, 10));

    //第二种,Mapper接口方式的调用,推荐这种使用方式。

    PageHelper.startPage(1, 10);

    List<Country> list = countryMapper.selectIf(1);

    //第三种,Mapper接口方式的调用,推荐这种使用方式。

    PageHelper.offsetPage(1, 10);

    List<Country> list = countryMapper.selectIf(1);

    //第四种,参数方法调用

    //存在以下 Mapper 接口方法,你不需要在 xml 处理后两个参数

    public interface CountryMapper {

        List<Country> selectByPageNumSize(

                @Param("user") User user,

                @Param("pageNum") int pageNum,

                @Param("pageSize") int pageSize);

    }

    //配置supportMethodsArguments=true

    //在代码中直接调用:

    List<Country> list = countryMapper.selectByPageNumSize(user, 1, 10);

    //第五种,参数对象

    //如果 pageNum 和 pageSize 存在于 User 对象中,只要参数有值,也会被分页

    //有如下 User 对象

    public class User {

        //其他fields

        //下面两个参数名和 params 配置的名字一致

        private Integer pageNum;

        private Integer pageSize;

    }

    //存在以下 Mapper 接口方法,你不需要在 xml 处理后两个参数

    public interface CountryMapper {

        List<Country> selectByPageNumSize(User user);

    }

    //当 user 中的 pageNum!= null && pageSize!= null 时,会自动分页

    List<Country> list = countryMapper.selectByPageNumSize(user);

    //第六种,ISelect 接口方式

    //jdk6,7用法,创建接口

    Page<Country> page = PageHelper.startPage(1, 10).doSelectPage(new ISelect() {

        @Override

        public void doSelect() {

            countryMapper.selectGroupBy();

        }

    });

    //jdk8 lambda用法

    Page<Country> page = PageHelper.startPage(1, 10).doSelectPage(()-> countryMapper.selectGroupBy());

    //也可以直接返回PageInfo,注意doSelectPageInfo方法和doSelectPage

    pageInfo = PageHelper.startPage(1, 10).doSelectPageInfo(new ISelect() {

        @Override

        public void doSelect() {

            countryMapper.selectGroupBy();

        }

    });

    //对应的lambda用法

    pageInfo = PageHelper.startPage(1, 10).doSelectPageInfo(() -> countryMapper.selectGroupBy());

    //count查询,返回一个查询语句的count数

    long total = PageHelper.count(new ISelect() {

        @Override

        public void doSelect() {

            countryMapper.selectLike(country);

        }

    });

    //lambda

    total = PageHelper.count(()->countryMapper.selectLike(country));

    下面对最常用的方式进行详细介绍

    1). RowBounds方式的调用

    List<Country> list = sqlSession.selectList("x.y.selectIf", null, new RowBounds(1, 10));

    使用这种调用方式时,你可以使用RowBounds参数进行分页,这种方式侵入性最小,我们可以看到,通过RowBounds方式调用只是使用了这个参数,并没有增加其他任何内容。

    分页插件检测到使用了RowBounds参数时,就会对该查询进行物理分页

    关于这种方式的调用,有两个特殊的参数是针对 RowBounds 的,你可以参看上面的 场景一 和 场景二

    注:不只有命名空间方式可以用RowBounds,使用接口的时候也可以增加RowBounds参数,例如:

    //这种情况下也会进行物理分页查询

    List<Country> selectAll(RowBounds rowBounds); 

    注意: 由于默认情况下的 RowBounds 无法获取查询总数,分页插件提供了一个继承自 RowBounds 的 PageRowBounds,这个对象中增加了 total 属性,执行分页查询后,可以从该属性得到查询总数。

    2). PageHelper.startPage 静态方法调用

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

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

    例一:

    //获取第1页,10条内容,默认查询总数count

    PageHelper.startPage(1, 10);

    //紧跟着的第一个select方法会被分页

    List<Country> list = countryMapper.selectIf(1);

    assertEquals(2, list.get(0).getId());

    assertEquals(10, list.size());

    //分页时,实际返回的结果list类型是Page<E>,如果想取出分页信息,需要强制转换为Page<E>

    assertEquals(182, ((Page) list).getTotal());

    例二:

    //request: url?pageNum=1&pageSize=10

    //支持 ServletRequest,Map,POJO 对象,需要配合 params 参数

    PageHelper.startPage(request);

    //紧跟着的第一个select方法会被分页

    List<Country> list = countryMapper.selectIf(1);

    //后面的不会被分页,除非再次调用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());

    例三,使用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());

    3). 使用参数方式

    想要使用参数方式,需要配置 supportMethodsArguments 参数为 true,同时要配置 params 参数。 例如下面的配置:

    <plugins>

        <!-- com.github.pagehelper为PageHelper类所在包名 -->

        <plugin interceptor="com.github.pagehelper.PageInterceptor">

            <!-- 使用下面的方式配置参数,后面会有所有的参数介绍 -->

            <property name="supportMethodsArguments" value="true"/>

            <property name="params" value="pageNum=pageNumKey;pageSize=pageSizeKey;"/>

    </plugin>

    </plugins>

    在 MyBatis 方法中:

    List<Country> selectByPageNumSize(

            @Param("user") User user,

            @Param("pageNumKey") int pageNum,

            @Param("pageSizeKey") int pageSize);

    当调用这个方法时,由于同时发现了 pageNumKey 和 pageSizeKey 参数,这个方法就会被分页。params 提供的几个参数都可以这样使用。

    除了上面这种方式外,如果 User 对象中包含这两个参数值,也可以有下面的方法:

    List<Country> selectByPageNumSize(User user);

    当从 User 中同时发现了 pageNumKey 和 pageSizeKey 参数,这个方法就会被分页。

    注意:pageNum 和 pageSize 两个属性同时存在才会触发分页操作,在这个前提下,其他的分页参数才会生效。

    3). PageHelper 安全调用

    1. 使用 RowBounds 和 PageRowBounds 参数方式是极其安全的

    2. 使用参数方式是极其安全的

    3. 使用 ISelect 接口调用是极其安全的

    ISelect 接口方式除了可以保证安全外,还特别实现了将查询转换为单纯的 count 查询方式,这个方法可以将任意的查询方法,变成一个 select count(*) 的查询方法。

    4. 什么时候会导致不安全的分页?

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

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

    如果代码在进入 Executor 前发生异常,就会导致线程不可用,这属于人为的 Bug(例如接口方法和 XML 中的不匹配,导致找不到 MappedStatement 时), 这种情况由于线程不可用,也不会导致 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>();

    }

    这种写法就能保证安全。

    如果你对此不放心,你可以手动清理 ThreadLocal 存储的分页参数,可以像下面这样使用:

    List<Country> list;

    if(param1 != null){

        PageHelper.startPage(1, 10);

        try{

            list = countryMapper.selectAll();

        } finally {

            PageHelper.clearPage();

        }

    } else {

        list = new ArrayList<Country>();

    }

    相关文章

      网友评论

          本文标题:PageHelper 代码中的调用!

          本文链接:https://www.haomeiwen.com/subject/upsplltx.html