https://www.cnblogs.com/gustavo

Gustavo's Blog

人类的赞歌是勇气的赞歌!

Mybatis输出完整Sql - Interceptor

@Intercepts(
        {
                @Signature(type = Executor.class, method = "query"
                        , args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}),
                @Signature(type = Executor.class, method = "query"
                        , args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class
                        , CacheKey.class, BoundSql.class}),
                @Signature(type = Executor.class, method = "update"
                        , args = {MappedStatement.class, Object.class}),
        }
)
@Slf4j
public class MybatisSqlLogInterceptor implements Interceptor {


    /**
     * 当语句中某个参数值过长,超过配置的阈值,会显示参数开头及下面的省略号
     */
    private static final String LONG_PARAM_DESC = ".....";
    @Setter
    Supplier<Long> slowSqlThreshold = () -> 1000L;      // NOSONAR
    @Setter
    Supplier<Long> paramLengthLogLimit = () -> 1024L;   // NOSONAR

    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        Object proceed;
        try {
            long start = System.currentTimeMillis();
            proceed = invocation.proceed();
            long costTime = System.currentTimeMillis() - start;
            if (costTime > slowSqlThreshold.get()) {
                SqlDetail sqlDetail = getSqlDetail(invocation);
                log.info("executeSql: {}  pararm:[{}]  methodName:[{}]  rowsNum:[{}]  elapsedTime:{}ms"
                        , sqlDetail.getSql()
                        , sqlDetail.getParam()
                        , sqlDetail.getMethodName()
                        , getReturnRows(proceed)
                        , costTime);
            }
        } catch (Exception exception) {
            SqlDetail sqlDetail = getSqlDetail(invocation);
            log.error("executeSql: {}  pararm:[{}]  methodName:[{}] "
                    , sqlDetail.getSql()
                    , sqlDetail.getParam()
                    , sqlDetail.getMethodName()
                    , exception);
            throw exception;
        }
        return proceed;
    }

    /**
     * 获取SQL语句和参数
     */
    @Nullable
    private SqlDetail getSqlDetail(Invocation invocation) {
        SqlDetail sqlDetail = new SqlDetail();
        MappedStatement mappedStatement = (MappedStatement) invocation.getArgs()[0];
        if (null != mappedStatement) {
            String methodLocate = mappedStatement.getId();
            sqlDetail.setMethodName(getMethodName(methodLocate, '.'));
        }
        Object parameter = null;
        if (invocation.getArgs().length > 1) {
            parameter = invocation.getArgs()[1];
        }
        //获取参数
        BoundSql boundSql = mappedStatement.getBoundSql(parameter);
        sqlDetail.setSql(boundSql.getSql());
        Configuration configuration = mappedStatement.getConfiguration();
        Object parameterObject = boundSql.getParameterObject();
        StringBuffer sqlParam = new StringBuffer(128);
        List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
        //参数遍历拼接
        if (parameterObject != null) {
            TypeHandlerRegistry typeHandlerRegistry = configuration.getTypeHandlerRegistry();
            // 如果根据parameterObject.getClass()可以找到对应的类型,则替换
            if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {
                String param = ConvertUtil.toString(parameterObject);
                sqlParam.append(param.length() > paramLengthLogLimit.get()
                        ? param.substring(0, paramLengthLogLimit.get().intValue()) + LONG_PARAM_DESC : param);
                sqlDetail.setParam(sqlParam.toString());
            } else {
                MetaObject metaObject = configuration.newMetaObject(parameterObject);
                for (ParameterMapping parameterMapping : parameterMappings) {
                    String propertyName = parameterMapping.getProperty();
                    if (metaObject.hasGetter(propertyName)) {
                        String param = ConvertUtil.toString(metaObject.getValue(propertyName));
                        sqlParam.append(param.length() > paramLengthLogLimit.get()
                                        ? param.substring(0, paramLengthLogLimit.get().intValue()) + LONG_PARAM_DESC
                                        : param)
                                .append(',');
                    }
                    if (boundSql.hasAdditionalParameter(propertyName)) {
                        String param = ConvertUtil.toString(boundSql.getAdditionalParameter(propertyName));
                        sqlParam.append(param.length() > paramLengthLogLimit.get() ?
                                        param.substring(0, paramLengthLogLimit.get().intValue()) + LONG_PARAM_DESC
                                        : param)
                                .append(',');
                    }
                }
            }
            if (sqlParam.length() > 0) {
                sqlDetail.setParam(sqlParam.deleteCharAt(sqlParam.length() - 1).toString());
            }
        }
        return sqlDetail;
    }

    private Integer getReturnRows(Object proceed) {
        if (proceed instanceof Collection) {
            return ((Collection<?>) proceed).size();
        }
        if (proceed instanceof Map) {
            return ((Map) proceed).size();
        }
        if (proceed instanceof Integer) {
            return (Integer) proceed;
        }
        return 0;
    }

    /**
     * 生成MyBatis拦截器代理对象
     **/
    @Override
    public Object plugin(Object target) {
        return Plugin.wrap(target, this);
    }

    /**
     * 设置插件属性
     */
    @Override
    public void setProperties(Properties properties) {
    }

    String getMethodName(String str, char separator) {
        if (str == null || str.length() == 0) {
            return str;
        }
        final int pos = str.lastIndexOf(separator);
        if (pos == -1) {
            return str;
        }
        final int secondPos = str.lastIndexOf(separator, pos - 1);
        if (secondPos == -1) {
            return str;
        }
        return str.substring(secondPos + 1);
    }

    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    @Accessors(chain = true)
    public static class SqlDetail {
        private String sql;
        private String param;
        private String methodName;
    }
}
posted @ 2024-02-21 11:25  BitBean  阅读(157)  评论(0编辑  收藏  举报