import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.ParameterMapping;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;

import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;

/**
 * MyBatis拦截器,用于拦截SQL查询无入参的场景,避免全表查询
 *
 */
@Intercepts({
        @Signature(type = Executor.class, method = "query",
                args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class})})
public class ParameterInterceptor implements Interceptor {

    private final Map<Object, Object> mappedStatementIdMap = new HashMap<Object, Object>();

    @Override
    public Object intercept(Invocation invocation) throws InvocationTargetException, IllegalAccessException {
        Object[] queryArgs = invocation.getArgs();

        MappedStatement mappedStatement = null;
        if (queryArgs[0] instanceof MappedStatement) {
            mappedStatement = (MappedStatement) queryArgs[0];
        }

        if (null != mappedStatement && mappedStatementIdMap.containsKey(mappedStatement.getId())) {
            // 获取SQL
            BoundSql boundSql = mappedStatement.getBoundSql(queryArgs[1]);

            List<ParameterMapping> parameterMappingList = boundSql.getParameterMappings();

            if (parameterMappingList.isEmpty()) {
                Profiler.businessAlarm(mappedStatement.getId(), "查询参数为空");
                throw new BadArgumentException("查询参数为空,请确认入参是否有值");
            }

        }

        return invocation.proceed();
    }

    @Override
    public Object plugin(Object target) {
        return Plugin.wrap(target, this);
    }

    @Override
    public void setProperties(Properties properties) {
        for (Object key : properties.keySet()) {
            mappedStatementIdMap.put(key, 1);
        }
    }
}

运单主档查询偶发会有无任何参数的查询,引发严重慢SQL,造成数据库磁盘繁忙度严重飚高,极大地影响了其他业务操作,而由于入口众多和交叉调用,如果在入口做参数校验工作量及风险都比较大,所以采用MyBatis的插件机制在dao层做拦截,直接拒绝掉无参数的查询,上线后就再没有出现过因无参查询而出现慢SQL而导致的磁盘繁忙情况;