Heim  >  Artikel  >  Datenbank  >  Wie nutzt Java den MySQL-Treiber-Interceptor, um zeitaufwändige Berechnungen der SQL-Ausführung zu implementieren?

Wie nutzt Java den MySQL-Treiber-Interceptor, um zeitaufwändige Berechnungen der SQL-Ausführung zu implementieren?

WBOY
WBOYnach vorne
2023-05-27 13:10:061023Durchsuche

Hintergrund

Eine Anforderung des Unternehmens besteht darin, dass die vorhandene Link-Tracking-Protokollkomponente das SQL-Ausführungszeitdrucken unterstützen muss. Die übliche Methode zur Implementierung der Link-Tracking ist die Implementierung eines Drittanbieter-Frameworks oder Die vom Tool bereitgestellte Interceptor-Schnittstelle oder Filterschnittstelle stellt für MySQL keine Ausnahme dar. Tatsächlich implementiert es lediglich die von MySQL gesteuerte Interceptor-Schnittstelle.

Spezifische Implementierung

MySQL-Kanäle haben unterschiedliche Versionen und die Interceptor-Schnittstellen verschiedener Versionen sind unterschiedlich, sodass Sie sie entsprechend den verschiedenen Versionen des MySQL-Treibers implementieren müssen In Bezug auf den Antwort-Interceptor werden wir die Implementierungsmethoden der MySQL-Kanalversionen 5, 6 und 8 vorstellen.

MySQL5

Hier nehmen wir die Version des MySQL-Kanals 5.1.18 als Beispiel für die Implementierung der StatementInterceptorV2-Schnittstelle, und die Hauptimplementierungslogik ist in Die Methoden preProcess code> und <code>postProcess müssen vor und nach der SQL-Ausführung ausgeführt werden. Das Framework, das ich verwende, ist MDC, um einen Zeitstempel vor der SQL-Ausführung aufzuzeichnen . Der Code befindet sich in der postProcess-Methode MDC.put("sql_exec_time", start);. Sie können ihn auch mit ThreadLocal usw. implementieren und dann verwenden die postProcess-MethodeMDC.get("sql_exec_time")Erhalten Sie die aufgezeichnete Zeit vor der SQL-Ausführung und subtrahieren Sie schließlich die Zeit vor der SQL-Ausführung vom aktuellen Zeitstempel, um die SQL-Ausführung zu berechnen Zeit. StatementInterceptorV2接口,主要实现逻辑在preProcesspostProcess方法,这两个方法是sql执行前后要执行的方法,我所使用的框架是logback,这里使用MDC来记录sql执行前的一个时间戳,代码在postProcess方法MDC.put("sql_exec_time", start);,自己也可以使用ThreadLocal等来实现,然后在postProcess方法中使用MDC.get("sql_exec_time")将记录的sql执行前的时间取出来,最后再用当前时间戳减去sql执行前的时间,就算出了sql执行的时间。

import static net.logstash.logback.marker.Markers.append;

import com.mysql.jdbc.Connection;
import com.mysql.jdbc.ResultSetInternalMethods;
import com.mysql.jdbc.Statement;
import com.mysql.jdbc.StatementInterceptorV2;
import com.redick.util.LogUtil;
import java.sql.SQLException;
import java.util.Properties;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.MDC;

/**
 * @author Redick01
 */
@Slf4j
public class Mysql5StatementInterceptor implements StatementInterceptorV2 {

    @Override
    public void init(Connection connection, Properties properties) throws SQLException {

    }

    @Override
    public ResultSetInternalMethods preProcess(String s, Statement statement, Connection connection)
            throws SQLException {
        String start = String.valueOf(System.currentTimeMillis());
        MDC.put("sql_exec_time", start);
        log.info(LogUtil.customizeMarker(LogUtil.kLOG_KEY_TRACE_TAG, "sql_exec_before"), "开始执行sql");
        return null;
    }

    @Override
    public boolean executeTopLevelOnly() {
        return false;
    }

    @Override
    public void destroy() {

    }

    @Override
    public ResultSetInternalMethods postProcess(String s, Statement statement,
            ResultSetInternalMethods resultSetInternalMethods, Connection connection, int i,
            boolean b, boolean b1, SQLException e) throws SQLException {
        long start = Long.parseLong(MDC.get("sql_exec_time"));
        long end = System.currentTimeMillis();
        log.info(LogUtil.customizeMarker(LogUtil.kLOG_KEY_TRACE_TAG, "sql_exec_after")
                .and(append(LogUtil.kLOG_KEY_SQL_EXEC_DURATION, end - start)), "结束执行sql");
        return null;
    }
}

MySQL6

MySQL6和MySQL5基本一样,只是接口不是同一个,直接放代码

import static net.logstash.logback.marker.Markers.append;

import com.mysql.cj.api.MysqlConnection;
import com.mysql.cj.api.jdbc.Statement;
import com.mysql.cj.api.jdbc.interceptors.StatementInterceptor;
import com.mysql.cj.api.log.Log;
import com.mysql.cj.api.mysqla.result.Resultset;
import com.redick.util.LogUtil;
import java.sql.SQLException;
import java.util.Properties;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.MDC;

/**
 * @author Redick01
 */
@Slf4j
public class Mysql6StatementInterceptor implements StatementInterceptor {

    @Override
    public StatementInterceptor init(MysqlConnection mysqlConnection, Properties properties,
            Log log) {
        return null;
    }

    @Override
    public <T extends Resultset> T preProcess(String s, Statement statement) throws SQLException {
        String start = String.valueOf(System.currentTimeMillis());
        MDC.put("sql_exec_time", start);
        log.info(LogUtil.customizeMarker(LogUtil.kLOG_KEY_TRACE_TAG, "sql_exec_before"), "开始执行sql");
        return null;
    }

    @Override
    public boolean executeTopLevelOnly() {
        return false;
    }

    @Override
    public void destroy() {

    }

    @Override
    public <T extends Resultset> T postProcess(String s, Statement statement, T t, int i, boolean b,
            boolean b1, Exception e) throws SQLException {
        long start = Long.parseLong(MDC.get("sql_exec_time"));
        long end = System.currentTimeMillis();
        log.info(LogUtil.customizeMarker(LogUtil.kLOG_KEY_TRACE_TAG, "sql_exec_after")
                .and(append(LogUtil.kLOG_KEY_SQL_EXEC_DURATION, end - start)), "结束执行sql");
        return null;
    }
}

MySQL8

MySQL8和MySQL5/6的拦截器接口又不一样了,MySQL8的拦截器接口是com.mysql.cj.interceptors.QueryInterceptor,统计sql执行时间的方式还是一样的,代码如下:

import static net.logstash.logback.marker.Markers.append;

import com.mysql.cj.MysqlConnection;
import com.mysql.cj.Query;
import com.mysql.cj.interceptors.QueryInterceptor;
import com.mysql.cj.log.Log;
import com.mysql.cj.protocol.Resultset;
import com.mysql.cj.protocol.ServerSession;
import com.redick.util.LogUtil;
import java.util.Properties;
import java.util.function.Supplier;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.MDC;

/**
 * @author Redick01
 */
@Slf4j
public class Mysql8QueryInterceptor implements QueryInterceptor {

    @Override
    public QueryInterceptor init(MysqlConnection mysqlConnection, Properties properties, Log log) {
        return null;
    }

    @Override
    public <T extends Resultset> T preProcess(Supplier<String> supplier, Query query) {
        String start = String.valueOf(System.currentTimeMillis());
        MDC.put("sql_exec_time", start);
        log.info(LogUtil.customizeMarker(LogUtil.kLOG_KEY_TRACE_TAG, "sql_exec_before"), "开始执行sql");
        return null;
    }

    @Override
    public boolean executeTopLevelOnly() {
        return false;
    }

    @Override
    public void destroy() {

    }

    @Override
    public <T extends Resultset> T postProcess(Supplier<String> supplier, Query query, T t,
            ServerSession serverSession) {
        long start = Long.parseLong(MDC.get("sql_exec_time"));
        long end = System.currentTimeMillis();
        log.info(LogUtil.customizeMarker(LogUtil.kLOG_KEY_TRACE_TAG, "sql_exec_after")
                .and(append(LogUtil.kLOG_KEY_SQL_EXEC_DURATION, end - start)), "结束执行sql");
        return null;
    }
}

使用方法

MySQL5和6的使用方式一样,在数据库链接的url中增加如下statementInterceptors参数,例如:

 url: jdbc:mysql://127.0.0.1:3316/log-helper?useUnicode=true&characterEncoding=UTF8&statementInterceptors=com.redick.support.mysql.Mysql5StatementInterceptor&serverTimezone=CST

MySQL8则是在url中增加queryInterceptors

url: jdbc:mysql://127.0.0.1:3316/log-helper?useUnicode=true&characterEncoding=UTF8&queryInterceptors=com.redick.support.mysql.Mysql8QueryInterceptor&serverTimezone=CST

MySQL6

MySQL6 und MySQL5 sind grundsätzlich gleich, aber die Schnittstelle ist nicht dieselbe. Geben Sie einfach den Code direkt ein

{"@timestamp":"2023-02-28T17:16:29.234+08:00","@version":"0.0.1","message":"开始执行sql","logger_name":"com.redick.support.mysql.Mysql5StatementInterceptor","thread_name":"http-nio-3321-exec-4","level":"INFO","level_value":20000,"traceId":"9ed930dc-4cc6-4719-bf33-9fcb618fd65b","spanId":"1","request_type":"getName","parentId":"0","trace_tag":"sql_exec_before"}

MySQL8# 🎜🎜##🎜🎜 #Die Interceptor-Schnittstellen von MySQL8 und MySQL5/6 sind unterschiedlich. Die Interceptor-Schnittstelle von MySQL8 ist com.mysql.cj.interceptors.QueryInterceptor. Die Methode zum Zählen der SQL-Ausführungszeit ist Immer noch derselbe. Der Code lautet wie folgt:

{"@timestamp":"2023-02-28T17:16:29.237+08:00","@version":"0.0.1","message":"结束执行sql","logger_name":"com.redick.support.mysql.Mysql5StatementInterceptor","thread_name":"http-nio-3321-exec-4","level":"INFO","level_value":20000,"traceId":"9ed930dc-4cc6-4719-bf33-9fcb618fd65b","spanId":"1","request_type":"getName","parentId":"0","trace_tag":"sql_exec_after","sql_duration":3}

Verwendungsmethode#🎜🎜##🎜🎜#MySQL5 und 6 werden auf die gleiche Weise verwendet. Fügen Sie den folgenden statementInterceptors hinzu Parameter zur URL der Datenbankverknüpfung hinzufügen, zum Beispiel: #🎜 🎜#rrreee#🎜🎜#MySQL8 fügt queryInterceptors-Parameter in die URL ein, zum Beispiel: #🎜🎜#rrreee#🎜🎜#Testergebnisse #🎜🎜##🎜🎜#SQL-Protokoll vor der Ausführung# 🎜🎜#rrreee#🎜🎜#SQL-Protokoll nach der Ausführung, der sql_duration-Bezeichner benötigt 3 ms, um sql#🎜🎜#rrreee auszuführen

Das obige ist der detaillierte Inhalt vonWie nutzt Java den MySQL-Treiber-Interceptor, um zeitaufwändige Berechnungen der SQL-Ausführung zu implementieren?. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Dieser Artikel ist reproduziert unter:yisu.com. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen