ホームページ  >  記事  >  データベース  >  Java は MySQL ドライバー インターセプターをどのように使用して、時間のかかる SQL 計算を実装しますか?

Java は MySQL ドライバー インターセプターをどのように使用して、時間のかかる SQL 計算を実装しますか?

WBOY
WBOY転載
2023-05-27 13:10:061080ブラウズ

背景

会社の要件の 1 つは、会社の既存のリンク トラッキング ログ コンポーネントが MySQL の SQL 実行時間の出力をサポートしている必要があるということです。リンク トラッキングを実装する一般的な方法は、サードパーティのフレームワークまたはツールを実装することです。 MySQL のインターセプター インターフェイスやフィルター インターフェイスも例外ではなく、実際には、MySQL によって駆動されるインターセプター インターフェイスを実装しているだけです。

具体的な実装

MySQL チャネルにはさまざまなバージョンがあり、さまざまなバージョンのインターセプター インターフェイスも異なるため、使用している MySQL ドライバーのさまざまなバージョンに応じて応答インターセプターを実装する必要があります。 . , 次に、MySQL チャネル 5、6、8 の実装方法をそれぞれ紹介します。

MySQL5

ここでは、StatementInterceptorV2 インターフェイスを実装するための例として MySQL チャネル 5.1.18 を取り上げます。主な実装ロジックは preProcess## にあります。 # と postProcess メソッド、これら 2 つのメソッドは SQL 実行の前後に実行されるメソッドです。私が使用するフレームワークは logback です。ここでは MDC を使用して、SQL 実行前のタイムスタンプを記録します。コードは # にあります。 ##postProcess メソッド。MDC.put("sql_exec_time", start);、ThreadLocal などを使用して実装し、MDC.get("sql_exec_time" を使用することもできます) ") の postProcess メソッド SQL 実行前の記録時間を取り出し、最後に現在のタイムスタンプから SQL 実行前の時間を減算して SQL 実行時間を計算します。 <pre class="brush:java;">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(&quot;sql_exec_time&quot;, start); log.info(LogUtil.customizeMarker(LogUtil.kLOG_KEY_TRACE_TAG, &quot;sql_exec_before&quot;), &quot;开始执行sql&quot;); 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(&quot;sql_exec_time&quot;)); long end = System.currentTimeMillis(); log.info(LogUtil.customizeMarker(LogUtil.kLOG_KEY_TRACE_TAG, &quot;sql_exec_after&quot;) .and(append(LogUtil.kLOG_KEY_SQL_EXEC_DURATION, end - start)), &quot;结束执行sql&quot;); return null; } }</pre>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

Interception MySQL8 と MySQL5/6 のインターセプタ インターフェイスがまた異なります。MySQL8 のインターセプタ インターフェイスは

com.mysql.cj.interceptors.QueryInterceptor

です。SQL 実行時間のカウント方法は同じです。コードは次のとおりです。 <pre class="brush:java;">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 &lt;T extends Resultset&gt; T preProcess(Supplier&lt;String&gt; supplier, Query query) { String start = String.valueOf(System.currentTimeMillis()); MDC.put(&quot;sql_exec_time&quot;, start); log.info(LogUtil.customizeMarker(LogUtil.kLOG_KEY_TRACE_TAG, &quot;sql_exec_before&quot;), &quot;开始执行sql&quot;); return null; } @Override public boolean executeTopLevelOnly() { return false; } @Override public void destroy() { } @Override public &lt;T extends Resultset&gt; T postProcess(Supplier&lt;String&gt; supplier, Query query, T t, ServerSession serverSession) { long start = Long.parseLong(MDC.get(&quot;sql_exec_time&quot;)); long end = System.currentTimeMillis(); log.info(LogUtil.customizeMarker(LogUtil.kLOG_KEY_TRACE_TAG, &quot;sql_exec_after&quot;) .and(append(LogUtil.kLOG_KEY_SQL_EXEC_DURATION, end - start)), &quot;结束执行sql&quot;); return null; } }</pre>Use Method

MySQL5 と 6 は同じ方法で使用されます。次の

statementInterceptors

パラメータをデータベース リンクの URL に追加します。例: <pre class="brush:yaml;"> url: jdbc:mysql://127.0.0.1:3316/log-helper?useUnicode=true&amp;characterEncoding=UTF8&amp;statementInterceptors=com.redick.support.mysql.Mysql5StatementInterceptor&amp;serverTimezone=CST</pre>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
テスト結果

SQL 実行前ログ

{"@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"}
#) ##SQL 実行後ログ、SQL_duration の識別には SQL の実行に 3 ミリ秒かかります

{"@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}

以上がJava は MySQL ドライバー インターセプターをどのように使用して、時間のかかる SQL 計算を実装しますか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事はyisu.comで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。