It’s not honest to print a SQL

Time:2021-3-5

It’s not honest to print a SQL

abstract

  1. When mybatis starts SQL printing, it does not splice parameters into SQL statements, which brings great inconvenience to local development
  2. Mybatis plus completes the combination of SQL statements and parameters by collecting logs. Some ideas do not support this plug-in well
  3. As long as it is started locally, it will output all queries and update SQL statements on the console, and monitor the SQL execution time

Here comes the gadget

  1. injection
@Configuration
public class MybatisConfig {
    @Bean
    @Conditional(LocalStartCondition.class)
    public SqlCheckInterceptor performanceInterceptor() {
        return new SqlCheckInterceptor();
    }
}
  1. Injection conditions
public class LocalStartCondition implements Condition {
    @Override
    public boolean matches(ConditionContext conditionContext, @Nullable AnnotatedTypeMetadata annotatedTypeMetadata) {
        return "local".equals(conditionContext.getEnvironment().getActiveProfiles()[0]);
    }
}
  1. Interceptor
@Intercepts({
        @Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}),
        @Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class}),
})
public class SqlCheckInterceptor implements Interceptor {

    private static final Log logger = LogFactory.getLog(SqlCheckInterceptor.class);
    private static final DateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        MappedStatement mappedStatement = (MappedStatement) invocation.getArgs()[0];
        Object parameterObject = null;
        if (invocation.getArgs().length > 1) {
            parameterObject = invocation.getArgs()[1];
        }
        long start = SystemClock.now();
        Object result = invocation.proceed();
        long timing = SystemClock.now() - start;
        String statementId = mappedStatement.getId();
        BoundSql boundSql = mappedStatement.getBoundSql(parameterObject);
        Configuration configuration = mappedStatement.getConfiguration();
        String sql = getSql(boundSql, parameterObject, configuration);
        if (logger.isInfoEnabled()) {
            String formatSqlStr = StringPool.NEWLINE +
                    "SQL-in-method===>:" + statementId + StringPool.NEWLINE +
                    "Execute-time====>:" + timing + " ms" + StringPool.NEWLINE +
                    "SQL-script===>:" + StringPool.NEWLINE +
                    sql + StringPool.NEWLINE;
            logger.info(formatSqlStr);
        }
        return result;
    }

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

    @Override
    public void setProperties(Properties properties) {
    }

    private String getSql(BoundSql boundSql, Object parameterObject, Configuration configuration) {
        String sql = boundSql.getSql().replaceAll("[\s]+", " ");
        List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
        TypeHandlerRegistry typeHandlerRegistry = configuration.getTypeHandlerRegistry();
        if (parameterMappings != null) {
            for (ParameterMapping parameterMapping : parameterMappings) {
                if (parameterMapping.getMode() != ParameterMode.OUT) {
                    Object value;
                    String propertyName = parameterMapping.getProperty();
                    if (boundSql.hasAdditionalParameter(propertyName)) {
                        value = boundSql.getAdditionalParameter(propertyName);
                    } else if (parameterObject == null) {
                        value = null;
                    } else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {
                        value = parameterObject;
                    } else {
                        MetaObject metaObject = configuration.newMetaObject(parameterObject);
                        value = metaObject.getValue(propertyName);
                    }
                    sql = replacePlaceholder(sql, value);
                }
            }
        }
        return sql;
    }

    private String replacePlaceholder(String sql, Object propertyValue) {
        String result;
        if (propertyValue != null) {
            if (propertyValue instanceof String) {
                result = "'" + propertyValue + "'";
            } else if (propertyValue instanceof Date) {
                result = "'" + DATE_FORMAT.format(propertyValue) + "'";
            } else {
                result = propertyValue.toString();
            }
        } else {
            result = "null";
        }
        return sql.replaceFirst("\?", Matcher.quoteReplacement(result));
    }
}

crap

**Paste code at the same time think about the implementation principle, to enhance the soul power is helpful. **