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());
    }


}

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