# Verwenden Sie den MyBatis-Interceptor, um eine vollständige Ausgabe der Mybatis-SQL-Konsole zu erzielen

Verwenden Sie den MyBatis-Interceptor, um eine vollständige Ausgabe der Mybatis-SQL-Konsole zu erzielen

Mybatis Abfangjäger

Einführung

  • Wie der Name schon sagt, muss ein Interceptor eine bestimmte Anforderung oder Schnittstelle abfangen, um bestimmte Vorgänge auszuführen. Beispielsweise können wir die HandlerInterceptor- Schnittstelle implementieren, die die Webanforderungsschnittstelle abfangen kann, um zu überprüfen, ob der Benutzer angemeldet ist.

  • Mit MyBatis können Sie Aufrufe an einem bestimmten Punkt während der Ausführung der zugeordneten Anweisung abfangen. Standardmäßig erlaubt MyBatis die Verwendung von Plug-Ins zum Abfangen von Methodenaufrufen, einschließlich:

  1. Methode zum Abfangen des Executors: Executor (Update, Abfrage, FlushStatements, Commit, Rollback, getTransaction, Schließen, isClosed)
  2. Parameterverarbeitung abfangen: ParameterHandler (getParameterObject, setParameters)
  3. Abfangen der Verarbeitung der Ergebnismenge: ResultSetHandler (handleResultSets, handleOutputParameters)
  4. Abfangen der SQL-Syntaxkonstruktion: StatementHandler (vorbereiten, parametrisieren, stapeln, aktualisieren, abfragen)

Vorschau des Quellcodes

Abfangjäger:

Mybatis verfügt nicht über eine Standardimplementierung dieser Schnittstelle. Sie können sie bei Bedarf entsprechend Ihren Anforderungen implementieren. Das Paging-Abfragetool pagehelper verfügt über eine Implementierung der Interceptor-Schnittstelle, um die Realisierung der Paging-Abfrage zu unterstützen.

public interface Interceptor {
    
    
    Object intercept(Invocation var1) throws Throwable;

    default Object plugin(Object target) {
    
    
        return Plugin.wrap(target, this);
    }

    default void setProperties(Properties properties) {
    
    
    }
}
Offizielle Interceptor-Instanz für die Website-Konfiguration
  • ExamplePlugin: Alle Aktualisierungsmethoden, die den Executor ausführen, werden von diesem Interceptor abgefangen.
@Intercepts({
    
    @Signature(
  type= Executor.class,
  method = "update",
  args = {
    
    MappedStatement.class,Object.class})})
public class ExamplePlugin implements Interceptor {
    
    
  public Object intercept(Invocation invocation) throws Throwable {
    
    
    return invocation.proceed();
  }
  public Object plugin(Object target) {
    
    
    return Plugin.wrap(target, this);
  }
  public void setProperties(Properties properties) {
    
    
  }
}
  • XML-Platzierung
<plugins>
    <plugin interceptor="org.format.mybatis.cache.interceptor.ExamplePlugin"></plugin>
</plugins>
  • Object Intercept (Invocation Invocation) ist der Ort, an dem die Interception-Logik implementiert wird. Intern ist es erforderlich, die Verantwortungskette durch invocation.proceed () explizit voranzutreiben, dh den nächsten Interceptor aufzurufen, der die Zielmethode abfängt.

  • Das Objekt-Plugin (Objektziel) besteht darin, den aktuellen Interceptor zu verwenden, um einen Proxy für das Ziel zu generieren. Dies erfolgt tatsächlich über Plugin.wrap (Ziel, dies), wobei das Zielziel und der Interzeptor dies an die Wrapper-Funktion übergeben werden.

  • Mit setProperties (Eigenschaften von Eigenschaften) werden zusätzliche Parameter festgelegt, die im Knoten Eigenschaften des Interceptors konfiguriert werden.

    Die Annotation beschreibt die Signatur [Typ, Methode, Argumente] der angegebenen Abfangmethode (dh welche Methode von welchem ​​Objekt abgefangen wird), die für die Entscheidung vor dem Abfangen verwendet wird.

Plugin.wrap-Methode
public staticObject wrap(Object target, Interceptor interceptor) {
    
    
    //从拦截器的注解中获取拦截的类名和方法信息
    Map<Class<?>, Set<Method>> signatureMap =getSignatureMap(interceptor);
    Class<?> type = target.getClass();
    //解析被拦截对象的所有接口(注意是接口)
    Class<?>[] interfaces = getAllInterfaces(type, signatureMap);
    if(interfaces.length > 0) {
    
    
        //生成代理对象, Plugin对象为该代理对象的InvocationHandler  
        returnProxy.newProxyInstance(type.getClassLoader(), interfaces, new Plugin(target,interceptor,signatureMap));
    }
    returntarget;
} 

Console Sql vollständige Ausgaberealisierung

  • SqlLoogerConfig
/**
 * @Description:Sql 完整输出sql
 * @Author:LiDong
 * @Create:2020/12/26
 * @Version:1.0.0
 */
@Configuration
public class SqlLoogerConfig {
    
    

    @Bean
    public SqlInterceptor sqlInterceptor() {
    
    
        return new SqlInterceptor();
    }
}
  • SqlInterceptor
package com.li.core.config.mybatis;

import com.github.pagehelper.util.StringUtil;
import org.apache.ibatis.cache.CacheKey;
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.mapping.ParameterMode;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
import org.apache.ibatis.type.TypeHandlerRegistry;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Properties;

/**
 * @Description:mybatis sql拦截器 控制打印出完整sql
 * @Author:LiDong
 * @Create:2020/12/26
 * @Version:1.0.0
 */
@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})}
)
public class SqlInterceptor implements Interceptor {
    
    

    private static final Logger logger = LoggerFactory.getLogger(SqlInterceptor.class);

    private static final ThreadLocal<SimpleDateFormat> DATETIME_FORMATTER = new ThreadLocal<SimpleDateFormat>() {
    
    
        @Override
        protected SimpleDateFormat initialValue() {
    
    
            return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        }
    };

    @Override
    public Object intercept(Invocation invocation) throws Throwable {
    
    
        Object result = null;
        //捕获掉异常,不要影响业务
        try {
    
    
            MappedStatement mappedStatement = (MappedStatement) invocation.getArgs()[0];
            Object parameter = null;
            if (invocation.getArgs().length > 1) {
    
    
                parameter = invocation.getArgs()[1];
            }
            String sqlId = mappedStatement.getId();
            BoundSql boundSql = mappedStatement.getBoundSql(parameter);
            Configuration configuration = mappedStatement.getConfiguration();

            long startTime = System.currentTimeMillis();

            try {
    
    
                result = invocation.proceed();
            } finally {
    
    
                long endTime = System.currentTimeMillis();
                long sqlCostTime = endTime - startTime;
                String sql = this.getSql(configuration, boundSql);
                this.formatSqlLog(sqlId, sql, sqlCostTime, result);
            }
            return result;

        } catch (Exception e) {
    
    
            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) {
    
    
    }

    /**
     * 获取完整的sql语句
     *
     * @param configuration
     * @param boundSql
     * @return
     */
    private String getSql(Configuration configuration, BoundSql boundSql) {
    
    
        // 输入sql字符串空判断
        String sql = boundSql.getSql();
        if (StringUtil.isEmpty(sql)) {
    
    
            return "";
        }
        return formatSql(sql, configuration, boundSql);
    }

    /**
     * 将占位符替换成参数值
     *
     * @param sql
     * @param configuration
     * @param boundSql
     * @return
     */
    private String formatSql(String sql, Configuration configuration, BoundSql boundSql) {
    
    
        //美化sql
        sql = beautifySql(sql);
        //填充占位符, 目前基本不用mybatis存储过程调用,故此处不做考虑
        Object parameterObject = boundSql.getParameterObject();
        List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
        TypeHandlerRegistry typeHandlerRegistry = configuration.getTypeHandlerRegistry();
        List<String> parameters = new ArrayList<>();
        if (parameterMappings != null) {
    
    
            MetaObject metaObject = parameterObject == null ? null : configuration.newMetaObject(parameterObject);
            for (int i = 0; i < parameterMappings.size(); i++) {
    
    
                ParameterMapping parameterMapping = parameterMappings.get(i);
                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 {
    
    
                        value = metaObject == null ? null : metaObject.getValue(propertyName);
                    }

                    if (value instanceof Number) {
    
    
                        parameters.add(String.valueOf(value));
                    } else {
    
    
                        StringBuilder builder = new StringBuilder();
                        builder.append("'");
                        if (value instanceof Date) {
    
    
                            builder.append(DATETIME_FORMATTER.get().format((Date) value));
                        } else if (value instanceof String) {
    
    
                            builder.append(value);
                        }
                        builder.append("'");
                        parameters.add(builder.toString());
                    }
                }
            }
        }

        for (String value : parameters) {
    
    
            sql = sql.replaceFirst("\\?", value);
        }
        return sql;
    }


    /**
     * 格式化sql日志
     *
     * @param sqlId
     * @param sql
     * @param costTime
     * @return
     */
    private void formatSqlLog(String sqlId, String sql, long costTime, Object obj) {
    
    
        String sqlLog = "=====> " + sql;
        StringBuffer result = new StringBuffer();
        if (obj instanceof List) {
    
    
            List list = (List) obj;
            int count = list.size();
            result.append("=====> Total:" + count);
        } else if (obj instanceof Integer) {
    
    
            result.append("=====> Total:" + obj);
        }
        result.append(" SpendTime:" + costTime + " ms");
        logger.info("\n------------------------------------------------------------------------------------------------------------------\n"
                + sqlLog + "\n" + result +
                "\n------------------------------------------------------------------------------------------------------------------");
    }


    public static String beautifySql(String sql) {
    
    
        sql = sql.replaceAll("[\\s\n ]+", " ");
        return sql;
    }
}

Effekt erzielen

Fügen Sie hier eine Bildbeschreibung ein

Ich denke du magst

Origin blog.csdn.net/qq_37248504/article/details/111767707
Empfohlen
Rangfolge