基于Mybatis分页插件PageHelper

时间:2022-10-17 10:13:06

基于Mybatis分页插件PageHelper

1.分页插件使用

1、POM依赖

PageHelper的依赖如下。需要新的版本可以去maven上自行选择

<!-- PageHelper 插件分页 -->
<dependency>
    <groupId>com.github.pagehelper</groupId>
    <artifactId>pagehelper</artifactId>
    <version>4.0.1</version>
</dependency>

2、Mybatis对PageHelper的配置

打开Mybatis配置文件,一般在Resource路径下mybatis-config.xml。

<configuration>
   <settings>
        <!-- 设置启用数据库字段下划线映射到java对象的驼峰式命名属性,默认为false -->
          <setting name="mapUnderscoreToCamelCase" value="true" />
     </settings>
     <objectWrapperFactory type="com.maomao.xwz.mybatis.handle.MapWrapperFactory"/>
    <plugins>
        <!-- com.github.pagehelper为PageHelper类所在包名 -->
        <plugin interceptor="com.github.pagehelper.PageHelper">
            <!-- 4.0.0以后版本可以不设置该参数 -->
            <property name="dialect" value="mysql"/>
            <!-- 该参数默认为false -->
            <!-- 设置为true时,会将RowBounds第一个参数offset当成pageNum页码使用 -->
            <!-- 和startPage中的pageNum效果一样-->
            <property name="offsetAsPageNum" value="true"/>
            <!-- 该参数默认为false -->
            <!-- 设置为true时,使用RowBounds分页会进行count查询 -->
            <property name="rowBoundsWithCount" value="true"/>
            <!-- 设置为true时,如果pageSize=0或者RowBounds.limit = 0就会查询出全部的结果 -->
            <!-- (相当于没有执行分页查询,但是返回结果仍然是Page类型)-->
            <property name="pageSizeZero" value="true"/>
            <!-- 3.3.0版本可用 - 分页参数合理化,默认false禁用 -->
            <!-- 启用合理化时,如果pageNum<1会查询第一页,如果pageNum>pages会查询最后一页 -->
            <!-- 禁用合理化时,如果pageNum<1或pageNum>pages会返回空数据 -->
            <property name="reasonable" value="false"/>
            <!-- 3.5.0版本可用 - 为了支持startPage(Object params)方法 -->
            <!-- 增加了一个`params`参数来配置参数映射,用于从Map或ServletRequest中取值 -->
            <!-- 可以配置pageNum,pageSize,count,pageSizeZero,reasonable,orderBy,不配置映射的用默认值 -->
            <!-- 不理解该含义的前提下,不要随便复制该配置 -->
            <property name="params" value="pageNum=start;pageSize=limit;"/>
            <!-- 支持通过Mapper接口参数来传递分页参数 -->
            <property name="supportMethodsArguments" value="true"/>
            <!-- always总是返回PageInfo类型,check检查返回类型是否为PageInfo,none返回Page -->
            <property name="returnPageInfo" value="check"/>
        </plugin>
    </plugins>
</configuration>

3、PageHelper分页使用

1)只统计查询总数量count

public PageInfo selectByExample() {
    PageHelper.startPage(1, -1);
    List list = this.baseMapper.selectByExample(new BsFeedbackExample());
    PageInfo pageInfo = new PageInfo(list);
    log.info(JSONObject.toJSONString(pageInfo));
    return pageInfo;
}

执行sql日志:

2)正常分页

public PageInfo selectByExample1() {
    PageHelper.startPage(1, 1);
    List list = this.baseMapper.selectByExample(new BsFeedbackExample());
    PageInfo pageInfo = new PageInfo(list);
    log.info(JSONObject.toJSONString(pageInfo));
    return pageInfo;
}

执行sql日志:

3)分页统计总数

public PageInfo selectByExample2() {
    PageHelper.startPage(1, 1, true);
    List list = this.baseMapper.selectByExample(new BsFeedbackExample());
    PageInfo pageInfo = new PageInfo(list);
    log.info(JSONObject.toJSONString(pageInfo));
    return pageInfo;
}

执行sql日志:

4) 分页不统计总数

public PageInfo selectByExample3() {
    PageHelper.startPage(1, 1, false);
    List list = this.baseMapper.selectByExample(new BsFeedbackExample());
    PageInfo pageInfo = new PageInfo(list);
    log.info(JSONObject.toJSONString(pageInfo));
    return pageInfo;
}

执行sql日志:

5) 查询全部数据

public PageInfo selectByExample3() {
    PageHelper.startPage(1, 0);
    List list = this.baseMapper.selectByExample(new BsFeedbackExample());
    PageInfo pageInfo = new PageInfo(list);
    log.info(JSONObject.toJSONString(pageInfo));
    return pageInfo;
}

执行sql日志:

6) 分页排序orderBy

public PageInfo selectByExample5() {
    String orderBy = "id desc";
    PageHelper.startPage(1, 2, orderBy);
    List list = this.baseMapper.selectByExample(new BsFeedbackExample());
    PageInfo pageInfo = new PageInfo(list);
    log.info(JSONObject.toJSONString(pageInfo));
    return pageInfo;
}

执行sql日志:

7) 直接传入分页参数RowBounds

public PageInfo selectByExample6() {
    List list = this.baseMapper.selectByExample(new BsFeedbackExample(), new RowBounds(2, 1));
    PageInfo pageInfo = new PageInfo(list);
    log.info(JSONObject.toJSONString(pageInfo));
    return pageInfo;
}

执行sql日志:

4、PageHelper如何确保安全性

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>();

}

2. PageHelper源码分析

1、 线程安全

PageHelper 方法使用了静态的 ThreadLocal 参数,分页参数和线程是绑定的。PageHelper.startPage方法调用后,将分页参数设置在ThreadLocal中。

/**
 * 基础分页方法
 *
 * @author liuzh
 */
public abstract class PageMethod {
    protected static final ThreadLocal<Page> LOCAL_PAGE = new ThreadLocal<Page>();
    protected static boolean DEFAULT_COUNT = true;
    /**
     * 开始分页
     *
     * @param pageNum      页码
     * @param pageSize     每页显示数量
     * @param count        是否进行count查询
     * @param reasonable   分页合理化,null时用默认配置
     * @param pageSizeZero true且pageSize=0时返回全部结果,false时分页,null时用默认配置
     */
    public static <E> Page<E> startPage(int pageNum, int pageSize, boolean count, Boolean reasonable, Boolean pageSizeZero) {
        Page<E> page = new Page<E>(pageNum, pageSize, count);
        page.setReasonable(reasonable);
        page.setPageSizeZero(pageSizeZero);
        //当已经执行过orderBy的时候
        Page<E> oldPage = getLocalPage();
        if (oldPage != null && oldPage.isOrderByOnly()) {
            page.setOrderBy(oldPage.getOrderBy());
        }
        setLocalPage(page);
        return page;
    }

/**
     * 开始分页
     *
     * @param offset 页码
     * @param limit  每页显示数量
     */
    public static <E> Page<E> offsetPage(int offset, int limit) {
        return offsetPage(offset, limit, DEFAULT_COUNT);
    }

/**
     * 开始分页
     *
     * @param offset 页码
     * @param limit  每页显示数量
     * @param count  是否进行count查询
     */
    public static <E> Page<E> offsetPage(int offset, int limit, boolean count) {
        Page<E> page = new Page<E>(new int[]{offset, limit}, count);
        //当已经执行过orderBy的时候
        Page<E> oldPage = getLocalPage();
        if (oldPage != null && oldPage.isOrderByOnly()) {
            page.setOrderBy(oldPage.getOrderBy());
        }
        setLocalPage(page);
        return page;
    }

/**
     * 排序
     *
     * @param orderBy
     */
    public static void orderBy(String orderBy) {
        Page<?> page = getLocalPage();
        if (page != null) {
            page.setOrderBy(orderBy);
        } else {
            page = new Page();
            page.setOrderBy(orderBy);
            page.setOrderByOnly(true);
            setLocalPage(page);
        }
    }

2、Mybatis分页拦截

定义了Mybatis拦截器,在Mybatis执行sql前,进行拦截,针对sql进行分页处理;
/**
 * Mybatis - 通用分页拦截器<br/>
 * 项目地址 : http://git.oschina.net/free/Mybatis_PageHelper
 *
 * @author liuzh/abel533/isea533
 * @version 5.0.0
 */
        @SuppressWarnings({"rawtypes", "unchecked"})
        @Intercepts(
                {
                        @Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}),
                        @Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class, CacheKey.class, BoundSql.class}),
                }
        )
        public class PageInterceptor implements Interceptor {
            //缓存count查询的ms
            protected Cache<String, MappedStatement> msCountMap = null;
            private Dialect dialect;
            private String default_dialect_class = "com.github.pagehelper.PageHelper";
            private Field additionalParametersField;
            private String countSuffix = "_COUNT";
            @Override
            public Object intercept(Invocation invocation) throws Throwable {

3、分页参数内置查询sql

MySqlDialect中加载AbstractHelperDialect实现,从线程中取出分页参数,生成分页sql;

经常提到的count查询,其实是PageHelper帮助我们生成的一个MappedStatement内存对象,它可以免去我们在XXXMapper.xml内单独声明一个sql count查询,我们只需要写一个sql分页业务查询即可。
/**
 * 针对 PageHelper 的实现
 *
 * @author liuzh
 * @since 2016-12-04 14:32
 */
public abstract class AbstractHelperDialect extends AbstractDialect implements Constant {

/**
     * 获取分页参数
     *
     * @param <T>
     * @return
     */
    public <T> Page<T> getLocalPage() {
        return PageHelper.getLocalPage();
    }

3.PageHelper使用建议

1、明确指定dialect(mysql)。

2、当业务sql存在内部嵌套时,明确编写sql分页业务和与它对应的count查询,别图省事。

MyBatis工具 http://www.mybatis.tk

推荐使用 Mybatis 通用 Mapper3 https://github.com/abel533/Mapper

推荐使用 Mybatis 分页插件 PageHelper https://github.com/pagehelper/Mybatis-PageHelper

推荐使用Mybatis介绍 http://www.mybatis.org/mybatis-3/zh/configuration.html#plugins

基于Mybatis分页插件PageHelper的更多相关文章

  1. Mybatis分页插件PageHelper的配置和使用方法

     Mybatis分页插件PageHelper的配置和使用方法 前言 在web开发过程中涉及到表格时,例如dataTable,就会产生分页的需求,通常我们将分页方式分为两种:前端分页和后端分页. 前端分 ...

  2. Mybatis分页插件PageHelper使用

    一. Mybatis分页插件PageHelper使用  1.不使用插件如何分页: 使用mybatis实现: 1)接口: List<Student> selectStudent(Map&lt ...

  3. Java SSM框架之MyBatis3(三)Mybatis分页插件PageHelper

    引言 对于使用Mybatis时,最头痛的就是写分页,需要先写一个查询count的select语句,然后再写一个真正分页查询的语句,当查询条件多了之后,会发现真不想花双倍的时间写count和select ...

  4. Mybatis学习---Mybatis分页插件 - PageHelper

    1. Mybatis分页插件 - PageHelper说明 如果你也在用Mybatis,建议尝试该分页插件,这个一定是最方便使用的分页插件. 该插件目前支持Oracle,Mysql,MariaDB,S ...

  5. Mybatis分页插件PageHelper的实现

    Mybatis分页插件PageHelper的实现 前言 分页这个概念在做web网站的时候很多都会碰到 说它简单吧 其实也简单 小型的网站,完全可以自己写一个,首先查出数据库总条数,然后按照分页大小分为 ...

  6. Mybatis分页插件-PageHelper的使用

    转载:http://blog.csdn.net/u012728960/article/details/50791343 Mybatis分页插件-PageHelper的使用 怎样配置mybatis这里就 ...

  7. (转)淘淘商城系列——MyBatis分页插件&lpar;PageHelper&rpar;的使用以及商品列表展示

    http://blog.csdn.net/yerenyuan_pku/article/details/72774381 上文我们实现了展示后台页面的功能,而本文我们实现的主要功能是展示商品列表,大家要 ...

  8. springmvc mybatis 分页插件 pagehelper

    springmvc mybatis 分页插件 pagehelper 下载地址:pagehelper 4.2.1 , jsqlparser 0.9.5 https://github.com/pagehe ...

  9. MyBatis 分页插件PageHelper 后台报错

    今天遇到一个问题,使用MyBatis 分页插件PageHelper 进行排序分页后,能正常返回正确的结果,但后台却一直在报错 net.sf.jsqlparser.parser.ParseExcepti ...

随机推荐

  1. 日常contest总结

    codeforces#352 div2 A 一个字符串的构造规律为1234567891011 问该字符串第i个数字是哪个 n<=1000 枚举即可 考虑这道题的拓展 当n=1e9的时候按位数枚举 ...

  2. R语言向量

    R语言基础:向量  心无咎 2012-04-02 13:37:00 向量(vector)1.seq():产生有规律的数列,间距省略时默认值为1.        例1:seq(10, 20, 0.5)  ...

  3. RESTful API你怎么看?

    关于RESTful 我结合自身实际工作经验说一说我的体验: 1. 统一资源定位方式 2. 统一行为方式 3. 简单统一就有力量 占位待续 如果觉得一个新东西学习门槛高,原因一般是什么? 约定太多,概念 ...

  4. Rsync企业实战之自动异地备份&lpar;转&rpar;

    认真的测试过网上的大多数文章和版本,真正能一次性测试通过的文章太少了,需要反复的推敲,反复的查阅资料,才能真正的测试成功,所以,在此背景下,总结了Rsync,加上自己的理解分享出来: 1. 原理篇 R ...

  5. 初识chromium thread的实现

    接触chromium已有一段时间,写点东西学习一下吧. 首先说一下用法,如何利用chromium封装好的thread类来开一个线程.在base里有一个封装该类的头文件thread.h,include它 ...

  6. SQLServer 安装以前的某个程序安装已在安装计算机上创建挂起的文件操作 解决办法

    http://wenku.baidu.com/view/6732fe09844769eae009ede2.html SQL Server 安装以前的某个程序安装已在安装计算机上创建挂起的文件操作 安装 ...

  7. 老李知识普及:web安全性的两大权威组织

    老李知识普及:web安全性的两大权威组织 两个重要的WEB应用安全组织-WASC/OWASPWeb Application Security Consortium (WASC)a.WEB应用安全标准的 ...

  8. Flink中的Time

    戳更多文章: 1-Flink入门 2-本地环境搭建&构建第一个Flink应用 3-DataSet API 4-DataSteam API 5-集群部署 6-分布式缓存 7-重启策略 8-Fli ...

  9. 1&period;0Tensorflow中出现编译问题的解决方案

    跑简单tf例程的时候遇到这个 sess = tf.Session(),I tensorflow/core/platform/cpu_feature_guard.cc:] Your CPU suppor ...

  10. HTML复习总结