您的位置 首页 java

MyBatis | 自定义插件实现输出可直接执行的SQL

Spring Boot 整合 MyBatis 项目中,控制台或日志文件中记录的 SQL 中的动态参数通常是不能自动填充的。排查问题时如果想要执行 sql ,还得手动把日志文件中记录的 SQL 中的 ? 替换为相应的参数。

为了使控制台或日志文件中记录的 SQL 复制到数据库图形化工具中时可以直接执行,我们开发了一个 MyBatis 插件。

拦截器代码实现

SqlPrintInterceptor.java —— 自定义 Mybatis 拦截器

 @Slf4j
@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 SqlPrintInterceptor implements Interceptor {
    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        List<Object> args = Lists.newArrayList(invocation.getArgs());
        MappedStatement mappedStatement = (MappedStatement) args.get(0);
        Object param = args.size() > 1 ? args.get(1) : null;
        // 开始时间
        long beginTimeMillis = System.currentTimeMillis();
        // SQL执行时间
        long costTimeMillis;
        // SQL执行结果
        Object result;
        try {
            result = invocation.proceed();
        } finally {
            costTimeMillis = System.currentTimeMillis() - beginTimeMillis;
        }

        BoundSql boundSql = mappedStatement.getBoundSql(param);
        // SQL,最初的SQL中含有?,我们会将SQL中的?替换成对应的参数(替换掉空格、 制表符 、换行或回车符)
         String  sql = boundSql.getSql().replaceAll("[\\s]+", " ");
        // Mapper参数对象
        Object parameterObject = boundSql.getParameterObject();
        // Mapper参数映射信息
        List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
        if (parameterMappings.size() > 0 && parameterObject != null) {
            TypeHandler Registry  typeHandlerRegistry = mappedStatement.getConfiguration().getTypeHandlerRegistry();
            if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {
                sql = sql.replaceFirst("\\?", getParameterValue(parameterObject));
            } else {
                MetaObject metaObject = mappedStatement.getConfiguration().newMetaObject(parameterObject);
                for (ParameterMapping parameterMapping : parameterMappings) {
                    String propertyName = parameterMapping.getProperty();
                    if (metaObject.hasGetter(propertyName)) {
                        Object obj = metaObject.getValue(propertyName);
                        String parameterValue = getParameterValue(obj);
                        sql = sql.replaceFirst("\\?", parameterValue);
                    } else if (boundSql.hasAdditionalParameter(propertyName)) {
                        Object obj = boundSql.getAdditionalParameter(propertyName);
                        String parameterValue = getParameterValue(obj);
                        sql = sql.replaceFirst("\\?", parameterValue);
                    }
                }
            }
        }
        log.info("sql: {}", sql);
        log.info("cost time millis: {}", costTimeMillis);

        return result;
    }

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

    @Override
    public  void  setProperties(Properties properties) {
        Interceptor.super.setProperties(properties);
    }

     private   static  String getParameterValue(Object obj) {
        String value;
        if (obj  instanceof  String) {
            value = new  StringBuffer ("'").append(obj).append("'").toString();
        } else if (obj instanceof Date) {
            DateFormat formatter = DateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.DEFAULT,  Locale .CHINA);
            value = new StringBuffer("'").append(formatter.format(new Date())).append("'").toString();
        } else {
            if (obj != null) {
                value = obj.toString();
            } else {
                value = "";
            }
        }
        return value.replace("$", "\\$");
    }
}  

拦截器配置

在 MyBatis 的配置文件里配置自定义拦截器:

 <plugins>
    <plugin interceptor="com.jasmine.plugin.SqlPrintInterceptor" />
</plugins>  

文章来源:智云一二三科技

文章标题:MyBatis | 自定义插件实现输出可直接执行的SQL

文章地址:https://www.zhihuclub.com/197944.shtml

关于作者: 智云科技

热门文章

网站地图