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.
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.
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
接口,主要实现逻辑在preProcess
和postProcess
方法,这两个方法是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和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和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
{"@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"}
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}
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ührenDas 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!