基于Mybatis分页插件PageHelper
基于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的更多相关文章
- Mybatis分页插件PageHelper的配置和使用方法
Mybatis分页插件PageHelper的配置和使用方法 前言 在web开发过程中涉及到表格时,例如dataTable,就会产生分页的需求,通常我们将分页方式分为两种:前端分页和后端分页. 前端分 ...
- Mybatis分页插件PageHelper使用
一. Mybatis分页插件PageHelper使用 1.不使用插件如何分页: 使用mybatis实现: 1)接口: List<Student> selectStudent(Map< ...
- Java SSM框架之MyBatis3(三)Mybatis分页插件PageHelper
引言 对于使用Mybatis时,最头痛的就是写分页,需要先写一个查询count的select语句,然后再写一个真正分页查询的语句,当查询条件多了之后,会发现真不想花双倍的时间写count和select ...
- Mybatis学习---Mybatis分页插件 - PageHelper
1. Mybatis分页插件 - PageHelper说明 如果你也在用Mybatis,建议尝试该分页插件,这个一定是最方便使用的分页插件. 该插件目前支持Oracle,Mysql,MariaDB,S ...
- Mybatis分页插件PageHelper的实现
Mybatis分页插件PageHelper的实现 前言 分页这个概念在做web网站的时候很多都会碰到 说它简单吧 其实也简单 小型的网站,完全可以自己写一个,首先查出数据库总条数,然后按照分页大小分为 ...
- Mybatis分页插件-PageHelper的使用
转载:http://blog.csdn.net/u012728960/article/details/50791343 Mybatis分页插件-PageHelper的使用 怎样配置mybatis这里就 ...
- (转)淘淘商城系列——MyBatis分页插件(PageHelper)的使用以及商品列表展示
http://blog.csdn.net/yerenyuan_pku/article/details/72774381 上文我们实现了展示后台页面的功能,而本文我们实现的主要功能是展示商品列表,大家要 ...
- springmvc mybatis 分页插件 pagehelper
springmvc mybatis 分页插件 pagehelper 下载地址:pagehelper 4.2.1 , jsqlparser 0.9.5 https://github.com/pagehe ...
- MyBatis 分页插件PageHelper 后台报错
今天遇到一个问题,使用MyBatis 分页插件PageHelper 进行排序分页后,能正常返回正确的结果,但后台却一直在报错 net.sf.jsqlparser.parser.ParseExcepti ...
随机推荐
- 云原生应用基金会CNCF
2006 年 8 月 9 日,埃里克·施密特(EricSchmidt)在搜索引擎大会上首次提出了“云计算”(Cloud Computing)的概念.一转眼十年过去了,它的发展势如破竹,不断渗透当代的 ...
- google adwords report相关类型
(来自enum的ReportDefinitionReportType) KEYWORDS_PERFORMANCE_REPORT, AD_PERFORMANCE_REPORT, URL_PE ...
- JAVA-Unit04: SQL(高级查询)
Unit04: SQL(高级查询) 查看SMITH的上司在那个城市工作? SELECT e.ename,m.ename,d.loc FROM emp e,emp m,dept d WHERE e.mg ...
- mac下导出JetBrains IDE Support插件给linux
自从google被和谐以后,上google的store安装插件是如此的费劲,好在mac下的chrome已经装好了,直接导出给linux就可以 mac下chrome的插件目录为 ~/Library/Ap ...
- String与StringBuffer效率的比较
String str = “”; for (int i=0; i<100; i++) str += “a”; 可是你知道在内存中会产生多少的垃圾出来吗?总共会有a.aa.aaa. aaa….,无 ...
- 应用程序 system 函数
1.使用实例 system("ps"); //执行shell命令ps 2.使用注意事项 system相当于创建了一个子进程,在子进程中调用程序.所以system执行的程序会继承主进 ...
- Memcached: 目录
ylbtech-Memcached: 目录 1.返回顶部 2.返回顶部 3.返回顶部 4.返回顶部 5.返回顶部 6.返回顶部 7.返回顶部 8.返回顶部 9.返回 ...
- 文档主题生成模型(LDA)
一.问题描述 1.1文本建模相关 统计文本建模的目的其实很简单:就是估算一组参数,这组参数使得整个语料库出现的概率最大.这是很简单的极大似然的思想了,就是认为观测到的样本的概率是最大的.建模的目标也是 ...
- node的socket.io的广播消息
在多个客户端与服务器端建立连接后,socket.io()服务器具有一个sockets属性,属性值为所有与客户端建立连接的socket对象.可以利用该对象的send方法或emit方法向所有客户端广播消息 ...
- javaweb地图定位demo
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/stri ...