赞
踩
情景再现:在给移动端提供分页查询数据接口时,知道他们不需要总条数。但是使用pagehelper 分页查询打印的sql总是会查询两次,先统计条数,在进行列表查询。对于有点强迫症的我来说,很不爽。于是开始查资料追源码。
于是找到了pagehelper的分页对象:
com.github.pagehelper.Page;
其中一个属性count默认是true,默认会执行count查询
/**
* 包含count查询
*/
private boolean count = true;
在执行分页列表查询前添加
PageHelper.startPage(page, size, false);
成功关闭count()查询
PageHelper中的其他方法也可以关闭count()查询,请读者自行查阅;
本来事情到此已经完美解决,但是因为我们是自己定义了一个Page对象(其实就是com.github.pagehelper.Page,写在本地的一个pojo)。查询的条件封装在一个对象中,并继承自定义的Page,然后尝试在自定义的Page中设置count为false,发现并不能生效。
1)在com.github.pagehelper.util.PageObjectUtil类中下面方法中找到了设置count属性的逻辑,
调用getParamValue(paramsObject, “count”, false);
public static <T> Page<T> getPageFromObject(Object params, boolean required) { ...... //count查询 Object _count = getParamValue(paramsObject, "count", false); if (_count != null) { page.setCount(Boolean.valueOf(String.valueOf(_count))); } //排序 if (hasOrderBy) { page.setOrderBy(orderBy.toString()); } //分页合理化 Object reasonable = getParamValue(paramsObject, "reasonable", false); if (reasonable != null) { page.setReasonable(Boolean.valueOf(String.valueOf(reasonable))); } //查询全部 Object pageSizeZero = getParamValue(paramsObject, "pageSizeZero", false); if (pageSizeZero != null) { page.setPageSizeZero(Boolean.valueOf(String.valueOf(pageSizeZero))); } }
2)从下图中的debug中可以看出getParamValue(paramsObject, “count”, false); 返回null,修改count属性失败
3)分析问题
使用PageHelper设置属性就能生效,是因为PageHelper设置属性的时候创建了一个本地的Page对象,并存储到本地。如下面的代码:
类位置:com.github.pagehelper.page.PageMethod /** * 开始分页 * * @param pageNum 页码 * @param pageSize 每页显示数量 * @param count 是否进行count查询 */ public static <E> Page<E> startPage(int pageNum, int pageSize, boolean count) { return startPage(pageNum, pageSize, count, null, null); } ...... /** * 开始分页 * * @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; }
在进行判断是否进行count查询的时候查找的是PageHelper中的page对象,所以设置的属性能够生效
2)在com.github.pagehelper.PageInterceptor中有是否执行count查询的条件 @Override public Object intercept(Invocation invocation) throws Throwable { ...... //判断是否需要进行 count 查询 if (dialect.beforeCount(ms, parameter, rowBounds)) { String countMsId = msId + countSuffix; Long count; //先判断是否存在手写的 count 查询 ........ } } 类位置:com.github.pagehelper.dialect.AbstractHelperDialect#beforeCount @Override public boolean beforeCount(MappedStatement ms, Object parameterObject, RowBounds rowBounds) { Page page = getLocalPage(); return !page.isOrderByOnly() && page.isCount(); }
page.isOrderByOnly() boolean类型 默认false,page.isCount()默认true;所以修改了page.isCount()为false
后,能够关闭count(0)查询
有下面方法可知:只要参数中有pageSize和pageNum,PageHelper 就会自动创建PageHelper 中的pege对象 实现分页逻辑。
路径:com.github.pagehelper.util.PageObjectUtil#getPageFromObject
public static <T> Page<T> getPageFromObject(Object params, boolean required) { ...... try { Object _pageNum = getParamValue(paramsObject, "pageNum", required); Object _pageSize = getParamValue(paramsObject, "pageSize", required); if (_pageNum == null || _pageSize == null) { if(hasOrderBy){ Page page = new Page(); page.setOrderBy(orderBy.toString()); page.setOrderByOnly(true); return page; } return null; } pageNum = Integer.parseInt(String.valueOf(_pageNum)); pageSize = Integer.parseInt(String.valueOf(_pageSize)); } catch (NumberFormatException e) { throw new PageException("分页参数不是合法的数字类型!"); } Page page = new Page(pageNum, pageSize); ...... }
在执行分页sql拼接时,在sql后拼接limit进行分页,在调用方言的时候拼接分页参数
1)路径:com.github.pagehelper.PageInterceptor#intercept ...... //判断是否需要进行分页查询 if (dialect.beforePage(ms, parameter, rowBounds)) { //生成分页的缓存 key CacheKey pageKey = cacheKey; //处理参数对象 parameter = dialect.processParameterObject(ms, parameter, boundSql, pageKey); //调用方言获取分页 sql String pageSql = dialect.getPageSql(ms, boundSql, parameter, rowBounds, pageKey); BoundSql pageBoundSql = new BoundSql(configuration, pageSql, boundSql.getParameterMappings(), parameter); //设置动态参数 for (String key : additionalParameters.keySet()) { pageBoundSql.setAdditionalParameter(key, additionalParameters.get(key)); } //执行分页查询 resultList = executor.query(ms, parameter, RowBounds.DEFAULT, resultHandler, pageKey, pageBoundSql); } else { //不执行分页的情况下,也不执行内存分页 resultList = executor.query(ms, parameter, RowBounds.DEFAULT, resultHandler, cacheKey, boundSql); } ....... 2)路径:com.github.pagehelper.dialect.helper.MySqlDialect#getPageSql @Override public String getPageSql(String sql, Page page, CacheKey pageKey) { StringBuilder sqlBuilder = new StringBuilder(sql.length() + 14); sqlBuilder.append(sql); if (page.getStartRow() == 0) { sqlBuilder.append(" LIMIT ? "); } else { sqlBuilder.append(" LIMIT ?, ? "); } pageKey.update(page.getPageSize()); return sqlBuilder.toString(); }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。