Mybatis Plus自动开启关闭分页 - 仅统计总数

一、背景

Mybatis Plus支持分页,但是需要在前端判断是否开启分页、是否统计总数,不支持仅统计总数

在大数据的分页查询时,limitcount常常有性能问题,需要根据容量评估来进行设计

常见的解决方式

  1. 将数据按字段排序,然后依据字段 > offsetId,滚动查询,不返回count总数
  2. 嵌套子查询获取offsetId(仅mysql)

等等等

本文仅讨论如何在Mybatis Plus中一个接口内实现分页、查全部、查总数

二、实现

接着上次文章Mybatis Plus自定义分页(自动开闭分页)

  1. 定义扩展PageParam
@Data
@ToString(callSuper = true)
@EqualsAndHashCode(callSuper = true)
public class PageParam<T> extends Page<T> {

    private static final long serialVersionUID = -3669295788865936942L;

    private Integer isOpenPage = 1;
    private Integer isSearchRecord = 1;

    @Override
    public long getSize() {
        if (1 == isOpenPage) {
            return super.getSize();
        }
        return -1;
    }

    @Override
    public long getTotal() {
        if (1 == isOpenPage) {
            return super.getTotal();
        }
        return getRecords().size();
    }
}
  1. 扩展PaginationInnerInterceptor

@NoArgsConstructor
public class PaginationExInnerInterceptor extends PaginationInnerInterceptor {

    /**
     * 这里进行count,如果count为0这返回false(就是不再执行sql了)
     */
    @Override
    public boolean willDoQuery(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
        IPage<?> page = ParameterUtils.findPage(parameter).orElse(null);
        if (page == null || page.getSize() < 0 || !page.isSearchCount()) {
            return isSearchRecord(page);
        }

        BoundSql countSql;
        MappedStatement countMs = buildCountMappedStatement(ms, page.countId());
        if (countMs != null) {
            countSql = countMs.getBoundSql(parameter);
        } else {
            countMs = buildAutoCountMappedStatement(ms);
            String countSqlStr = autoCountSql(page.optimizeCountSql(), boundSql.getSql());
            PluginUtils.MPBoundSql mpBoundSql = PluginUtils.mpBoundSql(boundSql);
            countSql = new BoundSql(countMs.getConfiguration(), countSqlStr, mpBoundSql.parameterMappings(), parameter);
            PluginUtils.setAdditionalParameter(countSql, mpBoundSql.additionalParameters());
        }

        CacheKey cacheKey = executor.createCacheKey(countMs, parameter, rowBounds, countSql);
        Object result = executor.query(countMs, parameter, rowBounds, resultHandler, cacheKey, countSql).get(0);
        page.setTotal(result == null ? 0L : Long.parseLong(result.toString()));

        return isSearchRecord(page) && continuePage(page);
    }

    private boolean isSearchRecord(IPage<?> page) {
        if (!(page instanceof PageParam)) {
            return true;
        }

        return BaseIsField.YES.val.equals(((PageParam<?>) page).getIsSearchRecord());
    }
}
  1. 优化

重写willDoQuery固然好,但当mybatis-plus升级版本修改了willDoQuery方法,那么存在不可控变化, 在修改内核代码时,最优的方式应该是扩展,而不是重写,故优化代码为

@NoArgsConstructor
public class PaginationExInnerInterceptor extends PaginationInnerInterceptor {

    /**
     * 这里进行count,如果count为0这返回false(就是不再执行sql了)
     */
    @Override
    public boolean willDoQuery(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
        boolean willDoQuery = super.willDoQuery(executor, ms, parameter, rowBounds, resultHandler, boundSql);
        IPage<?> page = ParameterUtils.findPage(parameter).orElse(null);
        if (page == null) {
            return willDoQuery;
        }
        return isSearchRecord(page) && willDoQuery;
    }

    private boolean isSearchRecord(IPage<?> page) {
        if (!(page instanceof PageParam)) {
            return true;
        }

        return BaseIsField.YES.val.equals(((PageParam<?>) page).getIsSearchRecord());
    }


}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章