zoukankan      html  css  js  c++  java
  • SpringBoot整合Pagehelper分页插件

    在web开发中,数据的分页是必不可少的。Pagehelper分页插件很强大,虽说平时我们不需要用到它的很多功能,但是了解下还是有必要的。

    官网:https://pagehelper.github.io/

    注:在 MyBatis下使用。本节是在 SpringBoot整合mybatis 基础上进行演示。

    一、引入依赖

    <!-- 核心启动器, 包括auto-configuration、logging and YAML -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter</artifactId>
    </dependency>
    <!-- 数据库操作需要的mysql 驱动包 -->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>5.1.48</version>
    </dependency>
    <!-- mybatis -->
    <dependency>
        <groupId>org.mybatis.spring.boot</groupId>
        <artifactId>mybatis-spring-boot-starter</artifactId>
        <version>2.1.1</version>
    </dependency>
    <!-- pagehelper -->
    <dependency>
        <groupId>com.github.pagehelper</groupId>
        <artifactId>pagehelper-spring-boot-starter</artifactId>
        <version>1.2.13</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
    </dependency>

    二、application.properties

    #这里要注意&,可能在spring的xml中我们用的是转义符号(&amp;),但是在这里不用
    spring.datasource.url=jdbc:mysql://192.168.178.5:12345/mydb?characterEncoding=utf8&useUnicode=true&useSSL=false&serverTimezone=UTC
    spring.datasource.username=root
    spring.datasource.password=123456
    spring.datasource.driver-class-name=com.mysql.jdbc.Driver
    spring.datasource.type=com.zaxxer.hikari.HikariDataSource
    
    ####### mybatis #######
    # 指定映射文件的具体位置
    mybatis.mapper-locations=classpath:mapper/*.xml
    
    ####### pagehelper #######
    # 默认情况下会使用 PageHelper 方式进行分页,如果想要实现自己的分页逻辑,
    # 可以实现 Dialect(com.github.pagehelper.Dialect) 接口,然后配置该属性为实现类的全限定名称。
    # 下面几个参数都是针对默认 dialect 情况下的参数。使用自定义 dialect 实现时(不推荐),下面的参数没有任何作用# 分页的数据库语言, oracle/mysql
    pagehelper.helper-dialect=mysql
    # 该参数对使用 RowBounds 作为分页参数时有效。 当该参数设置为 true 时,
    # 会将 RowBounds 中的 offset 参数当成 pageNum 使用,可以用页码和页面大小两个参数进行分页。
    pagehelper.offset-as-page-num= false
    # 该参数对使用 RowBounds 作为分页参数时有效。
    # 当该参数设置为true时,使用 RowBounds 分页会进行 count 查询。
    pagehelper.row-bounds-with-count=false
    # 当该参数设置为 true 时,如果 pageSize=0 或者 RowBounds.limit = 0
    # 就会查询出全部的结果(相当于没有执行分页查询,但是返回结果仍然是 Page 类型)。
    pagehelper.page-size-zero=false
    # 分页合理化参数,默认值为false。当该参数设置为 true 时,pageNum<=0 时会查询第一页,
    # pageNum>pages(超过总数时),会查询最后一页。默认false 时,直接根据参数进行查询。
    pagehelper.reasonable=true
    # 为了支持startPage(Object params)方法,增加了该参数来配置参数映射,
    # 用于从对象中根据属性名取值, 可以配置 pageNum,pageSize,count,pageSizeZero,reasonable,
    # 不配置映射的用默认值,
    # 默认值为pageNum=pageNum;pageSize=pageSize;count=countSql;reasonable=reasonable;pageSizeZero=pageSizeZero。
    pagehelper.params=pageNum=pageNum;pageSize=pageSize;count=countSql;reasonable=reasonable;pageSizeZero=pageSizeZero
    # 支持通过 Mapper 接口参数来传递分页参数,默认值false,分页插件会从查询方法的参数值中,
    # 自动根据上面 params 配置的字段中取值,查找到合适的值时就会自动分页。
    pagehelper.support-methods-arguments=
    # 当使用运行时动态数据源或没有设置 helperDialect 属性自动获取数据库类型时,
    # 会自动获取一个数据库连接, 通过该属性来设置是否关闭获取的这个连接,默认true关闭,
    # 设置为 false 后,不会关闭获取的连接,这个参数的设置要根据自己选择的数据源来决定。
    pagehelper.close-conn=true
    # 默认值为 false。设置为 true 时,允许在运行时根据多数据源自动识别对应方言的分页
    # (不支持自动选择sqlserver2012,只能使用sqlserver)
    pagehelper.auto-runtime-dialect=true

    三、PageHelper.startPage 静态方法调用

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

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

    public Page<Map<String,Object>> queryPage1(){
            //获取第1页,3条内容,默认查询总数count
            PageHelper.startPage(1, 3);
            //紧跟着的第一个select方法会被分页
            List<Map<String,Object>> list = userMapper.listUsers();
            // 分页时,实际返回的结果list类型是Page<E>,如果想取出分页信息,需要强制转换为Page<E>
            // 也可以這樣 PageInfo<Map<String, Object>> pageInfo = new PageInfo<Map<String, Object>>(list);
            Page<Map<String, Object>> pageInfo = (Page<Map<String, Object>>)list;
            return pageInfo;
    }
    
    public Page<Map<String,Object>> queryPage2(Map<String,Object> params){
        //参数包含pageNum=1 和 pageSize=10 都可以直接这样使用
        //支持 ServletRequest,Map,POJO 对象
        PageHelper.startPage(params);
        //紧跟着的第一个select方法会被分页
        List<Map<String,Object>> list = userMapper.listUsers();
        Page<Map<String, Object>> pageInfo = (Page<Map<String, Object>>)list;
    
        //后面的不会被分页,除非再次调用PageHelper.startPage
        List<Map<String,Object>> list2 = userMapper.listUsers();
        System.out.println("list2的大小是:" + list2.size());
        return pageInfo;
    }
    
    /**
     * 使用参数是安全的
     * 想要使用参数方式,需要配置 supportMethodsArguments 参数为 true,同时要配置 params 参数
     * 默认是pageSize和pageNum
     * 注:pageNum 和 pageSize 两个属性同时存在才会触发分页操作,在这个前提下,其他的分页参数才会生效。
     */
    public Page<Map<String,Object>> queryPage3(Map<String,Object> params){
        List<Map<String,Object>> list = userMapper.listUsers(params);
        Page<Map<String, Object>> pageInfo = (Page<Map<String, Object>>)list;
        return pageInfo;
    }
    
    /**
     * 使用 ISelect 接口调用是安全的
     * ISelect 接口方式除了可以保证安全外,还特别实现了将查询转换为单纯的 count 查询方式,
     * 这个方法可以将任意的查询方法,变成一个 select count(*) 的查询方法。
     *
     */
    public PageInfo<Map<String,Object>> queryPage4(){
        //分页,返回PageInfo分页对象
        PageInfo<Map<String,Object>> pageInfo = PageHelper.startPage(1, 10).doSelectPageInfo(new ISelect() {
            @Override
            public void doSelect() {
                userMapper.listUsers();
            }
        });
    
        //count查询,返回一个查询语句的count数
        long total = PageHelper.count(new ISelect() {
            @Override
            public void doSelect() {
                userMapper.listUsers();
            }
        });
        System.out.println("总记录数:" + total);
        return pageInfo;
    }

    四、什么时候会导致不安全的分页

    上面在讲解的例子提到分页安全,什么时候会导致不安全的分页?

    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>();
    }
  • 相关阅读:
    centos7 常用工具包安装
    Java.lang.String类
    javaweb系统调优方案
    nginx 优化
    centos7 源码安装nginx
    tomcat8调优
    commons-logging slf4j log4j 区别
    docker 安装centos7并SSH远程连接
    aws mysql 开启慢查询日志, 并利用mysqlsla 分析
    centos7 源码安装goaccess
  • 原文地址:https://www.cnblogs.com/myitnews/p/12349655.html
Copyright © 2011-2022 走看看