Skip to content

异步count模式(asyncCount=true),pageSize=0时未触发同步count的空结果提前返回逻辑,会执行不分页的全量数据查询 #879

@it-linnan

Description

@it-linnan

问题描述

业务中同时使用「查总条数」和「分页查询」场景,均启用asyncCount=true:
查总条数时设置pageSize=0(预期:仅触发count,不查询数据);
分页查询时设置pageSize>0(预期:正常分页)。
但发现异步count模式下,pageSize=0时未像同步count那样提前终止流程,反而执行了不必要的数据查询。

复现代码

// 场景1:查总条数(预期:仅异步count,不查数据)
Integer pageSize = 0;
PageHelper.startPage(currentPage, pageSize).asyncCount(true);

// 场景2:分页查询(预期:异步count+分页查询)
Integer pageSize = 50;
PageHelper.startPage(currentPage, pageSize).asyncCount(true);

问题分析

通过源码跟踪,发现同步/异步count的流程差异:

同步count流程(正常)

PageInterceptor#intercept:

if (dialect.beforeCount(ms, parameter, rowBounds)) {
    if (dialect.isAsyncCount()) {
        countFuture = asyncCount(ms, boundSql, parameter, rowBounds);
    } else {
        //查询总数
        Long count = count(executor, ms, parameter, rowBounds, null, boundSql);
        //处理查询总数,返回 true 时继续分页查询,false 时直接返回
        if (!dialect.afterCount(count, parameter, rowBounds)) {
            //当查询总数为 0 时,直接返回空的结果 <<<< pageSize=0直接返回空结果
            return dialect.afterPage(new ArrayList(), parameter, rowBounds);
        }
    }
}
// >>>> 仅count>0时才走分页查询
resultList = ExecutorUtil.pageQuery(dialect, executor, ms, parameter, rowBounds, resultHandler, boundSql, cacheKey);

异步count流程(异常)

PageInterceptor#intercept:

if (dialect.beforeCount(ms, parameter, rowBounds)) {
    if (dialect.isAsyncCount()) {
        countFuture = asyncCount(ms, boundSql, parameter, rowBounds);
    } else {
        ...
    }
}
// >>>> 异步count时,直接执行分页查询
resultList = ExecutorUtil.pageQuery(dialect, executor, ms, parameter, rowBounds, resultHandler, boundSql, cacheKey);

ExecutorUtil#pageQuery:

//判断是否需要进行分页查询
if (dialect.beforePage(ms, parameter, rowBounds)) { <<<< 调用dialect.beforePage判断是否需要分页
    ...
    //执行分页查询
    return executor.query(ms, parameter, RowBounds.DEFAULT, resultHandler, pageKey, pageBoundSql);
} else {
    //不执行分页的情况下,也不执行内存分页
    return executor.query(ms, parameter, RowBounds.DEFAULT, resultHandler, cacheKey, boundSql);
}

AbstractHelperDialect#beforePage:

public boolean beforePage(MappedStatement ms, Object parameterObject, RowBounds rowBounds) {
    Page page = getLocalPage();
    if (page.isOrderByOnly() || page.getPageSize() > 0) { <<<< pageSize为0, 返回false, 导致不执行分页逻辑
        return true;
    }
    return false;
}

异步count模式下,业务设置了pageSize=0,会执行不分页的全量数据查询

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions