若是想要将现有的select语句改成支持分页功能的查询语句该怎么作呢?
最简单的一种作法就是将全部的select语句都加上limit来实现分页,这种作法有什么问题呢?java
有没有一种简便方法实现呢?
Mybatis提供了plugin机制,容许咱们在Mybatis的原有处理流程上加入本身逻辑,全部咱们就可使用这种逻辑加上咱们的分页逻辑,也就是实现拦截器。
Mybatis支持的拦截的接口有4个,Executor、ParameterHandler、ResultSetHandler、StatementHandler。关于分页拦截器的配置和使用后期我会更新。
mysql
Mybatis的一个插件,PageHelper,很是方便mybatis分页查询。国内牛人的一个开源项目,有兴趣的能够去看源码。在github上仓库地址为:Mybatis-PageHelper。它支持基本主流与经常使用的数据库,这能够在它的文档上看到。这里记录一下使用的基本方法。PageHelpe开源地址:
github项目地址:https://github.com/pagehelper/Mybatis-PageHelper
码云 项目地址:http://git.oschina.net/free/Mybatis_PageHelpergit
首先引入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>
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