MyBaties分页插件PageHelper的简单使用

 

抛出问题:

若是想要将现有的select语句改成支持分页功能的查询语句该怎么作呢?
最简单的一种作法就是将全部的select语句都加上limit来实现分页,这种作法有什么问题呢?java

有没有一种简便方法实现呢?
Mybatis提供了plugin机制,容许咱们在Mybatis的原有处理流程上加入本身逻辑,全部咱们就可使用这种逻辑加上咱们的分页逻辑,也就是实现拦截器。
Mybatis支持的拦截的接口有4个,Executor、ParameterHandler、ResultSetHandler、StatementHandler。关于分页拦截器的配置和使用后期我会更新。
 mysql

1、PageHelper的介绍和使用

Mybatis的一个插件,PageHelper,很是方便mybatis分页查询。国内牛人的一个开源项目,有兴趣的能够去看源码。在github上仓库地址为:Mybatis-PageHelper。它支持基本主流与经常使用的数据库,这能够在它的文档上看到。这里记录一下使用的基本方法。PageHelpe开源地址:
github项目地址:https://github.com/pagehelper/Mybatis-PageHelper
码云 项目地址:http://git.oschina.net/free/Mybatis_PageHelpergit

 

2、项目配置

首先引入jar包依赖
<dependency>
    <groupId>com.github.pagehelper</groupId>
    <artifactId>pagehelper</artifactId>
    <version>4.1.4</version>
</dependency>

 

在mybatis的全局配置文件SqlMapConfig.xml中配置该插件
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <!-- 配置分页插件 -->
    <plugins>
        <plugin interceptor="com.github.pagehelper.PageHelper">
            <!-- 设置数据库类型 Oracle,Mysql,MariaDB,SQLite,Hsqldb,PostgreSQL六种数据库-->        
            <property name="dialect" value="mysql"/>
        </plugin>
    </plugins>
</configuration>

 

3、基本使用

dao层:github

public List<User> queryUserListLikeName(@Param("name") String name);

mapper.xml:sql

<select id="queryUserListLikeName" parameterType="String" resultType="User">
    SELECT * FROM tb_user WHERE name LIKE '%${name}%'
</select>

service.java
 数据库

public PageInfo<User> testQueryUserListLikeName() {
    //设置分页条件,Parameters:pageNum 页码pageSize 每页显示数量count 是否进行count查询
    PageHelper.startPage(1, 3, true);
    List<User> users = this.userMapper.queryUserListLikeName(null);
    //取分页后结果
    PageInfo<User> pageInfo = new PageInfo<User>(users);
   
    //打印分页信息
    System.out.println("数据总数:" + pageInfo.getTotal());
    System.out.println("数据总页数:" + pageInfo.getPages());
    System.out.println("最后一页:" + pageInfo.getLastPage());
    
    return pageInfo;
}

pageInfo.java安全

public class PageInfo<T> implements Serializable {
    private static final long serialVersionUID = 1L;
    //当前页
    private int pageNum;
    //每页的数量
    private int pageSize;
    //当前页的数量
    private int size;
 
    //因为startRow和endRow不经常使用,这里说个具体的用法
    //能够在页面中"显示startRow到endRow 共size条数据"
 
    //当前页面第一个元素在数据库中的行号
    private int startRow;
    //当前页面最后一个元素在数据库中的行号
    private int endRow;
    //总记录数
    private long total;
    //总页数
    private int pages;
    //结果集
    private List<T> list;
 
    //前一页
    private int prePage;
    //下一页
    private int nextPage;
 
    //是否为第一页
    private boolean isFirstPage = false;
    //是否为最后一页
    private boolean isLastPage = false;
    //是否有前一页
    private boolean hasPreviousPage = false;
    //是否有下一页
    private boolean hasNextPage = false;
    //导航页码数
    private int navigatePages;
    //全部导航页号
    private int[] navigatepageNums;
    //导航条上的第一页
    private int navigateFirstPage;
    //导航条上的最后一页
    private int navigateLastPage;
 
    public PageInfo() {
    }
 
    /**
     * 包装Page对象
     *
     * @param list
     */
    public PageInfo(List<T> list) {
        this(list, 8);
    }
 
    /**
     * 包装Page对象
     *
     * @param list          page结果
     * @param navigatePages 页码数量
     */
    public PageInfo(List<T> list, int navigatePages) {
        if (list instanceof Page) {
            Page page = (Page) list;
            this.pageNum = page.getPageNum();
            this.pageSize = page.getPageSize();
 
            this.pages = page.getPages();
            this.list = page;
            this.size = page.size();
            this.total = page.getTotal();
            //因为结果是>startRow的,因此实际的须要+1
            if (this.size == 0) {
                this.startRow = 0;
                this.endRow = 0;
            } else {
                this.startRow = page.getStartRow() + 1;
                //计算实际的endRow(最后一页的时候特殊)
                this.endRow = this.startRow - 1 + this.size;
            }
        } else if (list instanceof Collection) {
            this.pageNum = 1;
            this.pageSize = list.size();
 
            this.pages = this.pageSize > 0 ? 1 : 0;
            this.list = list;
            this.size = list.size();
            this.total = list.size();
            this.startRow = 0;
            this.endRow = list.size() > 0 ? list.size() - 1 : 0;
        }
        if (list instanceof Collection) {
            this.navigatePages = navigatePages;
            //计算导航页
            calcNavigatepageNums();
            //计算先后页,第一页,最后一页
            calcPage();
            //判断页面边界
            judgePageBoudary();
        }
    }
 
 
.......
}

注意:

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的基本使用,简单方便的分页插件。mybatis

相关文章
相关标签/搜索