基础组件-对Mybatis返回条数限制

一、目的
     限制单条SQL从数据库、拉取过多数据到应用端,防止应用内存过高,数据库IO过高等问题
二、开启限制
     加入该特性,只要引用基础框架包自动加入限制,限制数据量默认为1w条
三、关闭限制
     如果需要关闭该特新,在配置文件设置该属性,并重启
     -----properties---------------
     #关闭、默认开始
     sc.mybatis.plugin.enabled=false
    -----properties---------------
四、修改限制数量
     -----properties---------------
     #关闭、默认开始
     sc.mybatis.plugin.max.rows=10000
    -----properties---------------
五、升级优化
    异常抛出策略,在超出限制条数的时候可以选择抛出异常
     -----properties---------------
     #关闭、默认false
     sc.mybatis.plugin.throw.exception=false
    -----properties---------------
六、开发规范
    单条SQL数据量过大建议使用分页查询,减轻数据库和应用压力,避免内存溢出
七、实现原理
    通过mybatis拦截器,拦截StatementHandler,给Statement设置maxRows实现
核心代码:

@Slf4j
@Intercepts(
        {@Signature(type = StatementHandler.class, method = "query", args = {Statement.class, ResultHandler.class})}
        )
public class SQLStatementHandlerInterceptor implements Interceptor {
    /**
     * 限制返回条数
     *
     * @param invocation
     * @return
     * @throws Throwable
     */
    private int maxRows;

    public SQLStatementHandlerInterceptor(int maxRows) {
        this.maxRows = maxRows;
    }

    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        Object[] args = invocation.getArgs();
        if (null != args && args.length > 0) {
            try {
                if (maxRows > 0) {
                    Statement statement = (Statement) args[0];
                    statement.setMaxRows(maxRows);
                } else {
                    // 小于0,不做处理,默认取所有数据
                }
            } catch (SQLException e) {
                log.error("不支持设置maxRows");
            }

        }
        return invocation.proceed();
    }

    public int getMaxRows() {
        return maxRows;
    }

    public void setMaxRows(int maxRows) {
        this.maxRows = maxRows;
    }
}

抛出异常核心代码:

@Slf4j
@Intercepts(
        {@Signature(type = ResultHandler.class, method = "handleResultSets", args = {Statement.class})}
        )
public class ResultHandlerInterceptor implements Interceptor {

    /**
     * Apollo配置限制返回条数
     *
     * @param invocation
     * @return
     * @throws Throwable
     */
    @Value("${sc.mybatis.plugin.max.rows:10000}")
    private int maxRows;
    /**
     * apollo配置是否抛出异常
     */
    @Value("${sc.mybatis.plugin.throw.exception:false}")
    private boolean throwException;

    public ResultHandlerInterceptor(int maxRows) {
        this.maxRows = maxRows;
    }

    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        List result = (List) invocation.proceed();
        if(CollectionUtils.isEmpty(result)){
            return  null;
        }
        // 不走限制逻辑
        if(maxRows < 0){
            return result;
        }
        // 超出限制,抛出异常
        int size = result.size();
        if(size > maxRows){
            if(throwException){
                log.error("数据库单条SQL查询超出框架包mybatis限制,并且抛出异常,可以关闭mybatis限制功能或者修改限制条数或者关闭异常");
                throw new RuntimeException("数据库查询超时mybatis插件限制maxRows="+maxRows);
            }else {
                if(size -1 >0){
                    result = result.subList(0,size -1);
                }
            }
        }

        return result;
    }

}

你可能感兴趣的:(技术方案,mybatis)