pagehelper 关闭count(0)查询 以及pagehelper的分页原理分析

情景再现:在给移动端提供分页查询数据接口时,知道他们不需要总条数。但是使用pagehelper 分页查询打印的sql总是会查询两次,先统计条数,在进行列表查询。对于有点强迫症的我来说,很不爽。于是开始查资料追源码。

于是找到了pagehelper的分页对象:
com.github.pagehelper.Page;
其中一个属性count默认是true,默认会执行count查询
    /**
     * 包含count查询
     */
    private boolean count = true;

1.关闭count()查询

在执行分页列表查询前添加
PageHelper.startPage(page, size, false);

成功关闭count()查询
PageHelper中的其他方法也可以关闭count()查询,请读者自行查阅;

2.抛出问题

本来事情到此已经完美解决,但是因为我们是自己定义了一个Page对象(其实就是com.github.pagehelper.Page,写在本地的一个pojo)。查询的条件封装在一个对象中,并继承自定义的Page,然后尝试在自定义的Page中设置count为false,发现并不能生效。

3.原因查找

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)查询

4.讨论一个问题,为什么使用本地对象也能够使PageHelper 进行分页?

有下面方法可知:只要参数中有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);
		......
}

5.PageHelper 实现分页的原理

在执行分页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();
    }
  • 11
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
PageHelper是一个开源的Java分页插件,它可以方便地实现分页查询功能。使用PageHelper,你可以在查询数据时,通过简单的配置来实现自动分页。 以下是使用PageHelper实现分页查询的步骤: 1. 引入PageHelper依赖:在你的项目中,需要添加PageHelper的依赖。你可以通过在pom.xml文件中添加以下依赖来引入PageHelper: ```xml <dependency> <groupId>com.github.pagehelper</groupId> <artifactId>pagehelper-spring-boot-starter</artifactId> <version>最新版本</version> </dependency> ``` 请注意替换"最新版本"为你想要使用的PageHelper版本号。 2. 配置PageHelper:在Spring Boot项目中,你可以在application.properties或application.yml文件中添加以下配置: ```properties # 使用PageHelper进行分页 pagehelper.helper-dialect=mysql pagehelper.reasonable=true pagehelper.support-methods-arguments=true pagehelper.params=count=countSql pagehelper.auto-dialect=true ``` 这里使用了MySQL数据库作为示例,如果你使用其他数据库,请根据实际情况修改`pagehelper.helper-dialect`的值。 3. 在需要进行分页查询的方法上使用PageHelper:在你的DAO层或Service层的方法中,使用PageHelper.startPage方法开启分页功能,然后进行查询操作。 ```java import com.github.pagehelper.PageHelper; public List<User> getUsers(int pageNum, int pageSize) { // 开启分页 PageHelper.startPage(pageNum, pageSize); // 执行查询操作 List<User> userList = userDao.getUsers(); return userList; } ``` 在上述代码中,`pageNum`表示当前页码,`pageSize`表示每页显示的记录数。你可以根据需要调整这两个参数。 通过以上步骤,你就可以使用PageHelper来实现分页查询功能了。它会自动在查询语句中添加分页的SQL语句,并返回分页后的结果。 希望对你有所帮助!如果你还有其他问题,请随时提问。
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值