最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

java通過MySQL驅(qū)動(dòng)攔截器實(shí)現(xiàn)執(zhí)行sql耗時(shí)計(jì)算

 更新時(shí)間:2023年03月20日 14:25:14   作者:Redick01  
本文主要介紹了java通過MySQL驅(qū)動(dòng)攔截器實(shí)現(xiàn)執(zhí)行sql耗時(shí)計(jì)算,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

背景

公司的一個(gè)需求,公司既有的鏈路追蹤日志組件要支持MySQL的sql執(zhí)行時(shí)間打印,要實(shí)現(xiàn)鏈路追蹤常用的手段就是實(shí)現(xiàn)第三方框架或工具提供的攔截器接口或者是過濾器接口,對(duì)于MySQL也不例外,實(shí)際上就是實(shí)現(xiàn)了MySQL驅(qū)動(dòng)的攔截器接口而已。

具體實(shí)現(xiàn)

MySQL的渠道有不同的版本,不同版本的攔截器接口是不同的,所以要針對(duì)你所使用的不同版本的MySQL驅(qū)動(dòng)去實(shí)現(xiàn)響應(yīng)的攔截器,接下來分別介紹下MySQL渠道5,6,8版本的實(shí)現(xiàn)方式。

MySQL5

這里以MySQL渠道5.1.18版本為例實(shí)現(xiàn),實(shí)現(xiàn)StatementInterceptorV2接口,主要實(shí)現(xiàn)邏輯在preProcesspostProcess方法,這兩個(gè)方法是sql執(zhí)行前后要執(zhí)行的方法,我所使用的框架是logback,這里使用MDC來記錄sql執(zhí)行前的一個(gè)時(shí)間戳,代碼在postProcess方法MDC.put("sql_exec_time", start);,自己也可以使用ThreadLocal等來實(shí)現(xiàn),然后在postProcess方法中使用MDC.get("sql_exec_time")將記錄的sql執(zhí)行前的時(shí)間取出來,最后再用當(dāng)前時(shí)間戳減去sql執(zhí)行前的時(shí)間,就算出了sql執(zhí)行的時(shí)間。

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"), "開始執(zhí)行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)), "結(jié)束執(zhí)行sql");
        return null;
    }
}

MySQL6

MySQL6和MySQL5基本一樣,只是接口不是同一個(gè),直接放代碼

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"), "開始執(zhí)行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)), "結(jié)束執(zhí)行sql");
        return null;
    }
}

MySQL8

MySQL8和MySQL5/6的攔截器接口又不一樣了,MySQL8的攔截器接口是com.mysql.cj.interceptors.QueryInterceptor,統(tǒng)計(jì)sql執(zhí)行時(shí)間的方式還是一樣的,代碼如下:

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"), "開始執(zhí)行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)), "結(jié)束執(zhí)行sql");
        return null;
    }
}

使用方法

MySQL5和6的使用方式一樣,在數(shù)據(jù)庫鏈接的url中增加如下statementInterceptors參數(shù),例如:

 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參數(shù),例如:

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

測(cè)試結(jié)果

sql執(zhí)行前日志

{"@timestamp":"2023-02-28T17:16:29.234+08:00","@version":"0.0.1","message":"開始執(zhí)行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執(zhí)行后日志,sql_duration標(biāo)識(shí)執(zhí)行sql耗時(shí)3ms

{"@timestamp":"2023-02-28T17:16:29.237+08:00","@version":"0.0.1","message":"結(jié)束執(zhí)行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}

具體實(shí)現(xiàn)代碼參考基于Spring AOP + logstash-logback-encoder日志鏈路追蹤工具LogHelper

到此這篇關(guān)于java通過MySQL驅(qū)動(dòng)攔截器實(shí)現(xiàn)執(zhí)行sql耗時(shí)計(jì)算的文章就介紹到這了,更多相關(guān)java執(zhí)行sql耗時(shí)計(jì)算內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java 多個(gè)異常共享同一個(gè)異常處理器的方法

    Java 多個(gè)異常共享同一個(gè)異常處理器的方法

    這篇文章主要介紹了Java 多個(gè)異常共享同一個(gè)異常處理器的方法,Java 的異常處理機(jī)制,在 Java 7 中有了非常大的改進(jìn)。其中一個(gè)特性就是,支持多個(gè)異常共享同一個(gè)異常處理器。,需要的朋友可以參考下
    2019-06-06
  • 詳解5種Java中常見限流算法

    詳解5種Java中常見限流算法

    在高并發(fā)系統(tǒng)中,出于系統(tǒng)保護(hù)角度考慮,通常會(huì)對(duì)流量進(jìn)行限流;不但在工作中要頻繁使用,而且也是面試中的高頻考點(diǎn)。本文就為大家整理了5種Java中常見限流算法,需要的可以參考一下
    2023-04-04
  • 使用springboot對(duì)linux進(jìn)行操控的方法示例

    使用springboot對(duì)linux進(jìn)行操控的方法示例

    這篇文章主要介紹了使用springboot對(duì)linux進(jìn)行操控的方法示例,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-11-11
  • 詳解JAVA Spring 中的事件機(jī)制

    詳解JAVA Spring 中的事件機(jī)制

    這篇文章主要介紹了JAVA Spring 中的事件機(jī)制的相關(guān)資料,文中示例代碼非常細(xì)致,幫助大家更好的理解和學(xué)習(xí),感興趣的朋友可以了解下
    2020-07-07
  • Springboot打包部署項(xiàng)目的過程詳解

    Springboot打包部署項(xiàng)目的過程詳解

    這篇文章主要介紹了Springboot打包部署項(xiàng)目的過程,通過jar包方式打包和war方式打包,本文結(jié)合示例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧
    2023-12-12
  • java中struts2實(shí)現(xiàn)文件上傳下載功能

    java中struts2實(shí)現(xiàn)文件上傳下載功能

    這篇文章主要介紹了java中struts2實(shí)現(xiàn)文件上傳下載功能的方法,以實(shí)例形式分析了struts2文件上傳下載功能的實(shí)現(xiàn)技巧與相關(guān)問題,具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2016-05-05
  • Java編寫實(shí)現(xiàn)登陸窗口

    Java編寫實(shí)現(xiàn)登陸窗口

    這篇文章主要為大家詳細(xì)介紹了Java編寫實(shí)現(xiàn)登陸窗口,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-04-04
  • 深入講解SpringBoot Actuator是什么

    深入講解SpringBoot Actuator是什么

    Spring Boot Actuator提供了生產(chǎn)上經(jīng)常用到的功能(如健康檢查,審計(jì),指標(biāo)收集,HTTP跟蹤等),幫助我們監(jiān)控和管理Spring Boot應(yīng)用程序。這些功能都可以通過JMX或HTTP端點(diǎn)訪問
    2023-01-01
  • Java AbstractMethodError原因案例詳解

    Java AbstractMethodError原因案例詳解

    這篇文章主要介紹了Java AbstractMethodError原因案例詳解,本篇文章通過簡(jiǎn)要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下
    2021-08-08
  • java發(fā)送heartbeat心跳包(byte轉(zhuǎn)16進(jìn)制)

    java發(fā)送heartbeat心跳包(byte轉(zhuǎn)16進(jìn)制)

    這篇文章主要介紹了java發(fā)送heartbeat心跳包(byte轉(zhuǎn)16進(jìn)制),需要的朋友可以參考下
    2014-05-05

最新評(píng)論

平乐县| 龙里县| 伊春市| 山丹县| 永兴县| 马公市| 罗甸县| 昌江| 武安市| 澄城县| 淄博市| 普兰县| 北碚区| 江都市| 辛集市| 安徽省| 陆丰市| 米林县| 黔江区| 贵阳市| 河西区| 察隅县| 自治县| 皮山县| 灵丘县| 永靖县| 简阳市| 安仁县| 莒南县| 高州市| 开封市| 台安县| 高雄市| 肇源县| 弋阳县| 社旗县| 枣强县| 洛阳市| 武安市| 青阳县| 江安县|