iis服务器助手广告广告
返回顶部
首页 > 资讯 > 数据库 >java通过MySQL驱动拦截器实现执行sql耗时计算
  • 469
分享到

java通过MySQL驱动拦截器实现执行sql耗时计算

javasql耗时计算MySQL驱动拦截器耗时计算 2023-03-20 14:03:37 469人浏览 八月长安
摘要

目录背景具体实现Mysql5mysql6Mysql8使用方法测试结果背景 公司的一个需求,公司既有的链路追踪日志组件要支持MySQL的sql执行时间打印,要实现链路追踪常用的手段就是

背景

公司的一个需求,公司既有的链路追踪日志组件要支持MySQL的sql执行时间打印,要实现链路追踪常用的手段就是实现第三方框架工具提供的拦截器接口或者是过滤器接口,对于MySQL也不例外,实际上就是实现了MySQL驱动的拦截器接口而已。

具体实现

MySQL的渠道有不同的版本,不同版本的拦截器接口是不同的,所以要针对你所使用的不同版本的MySQL驱动去实现响应的拦截器,接下来分别介绍下MySQL渠道5,6,8版本的实现方式。

MySQL5

这里以MySQL渠道5.1.18版本为例实现,实现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;


@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;


@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;


@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

测试结果

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耗时3ms

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

具体实现代码参考基于spring aop + logstash-logback-encoder日志链路追踪工具LogHelper

到此这篇关于java通过MySQL驱动拦截器实现执行sql耗时计算的文章就介绍到这了,更多相关java执行sql耗时计算内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

您可能感兴趣的文档:

--结束END--

本文标题: java通过MySQL驱动拦截器实现执行sql耗时计算

本文链接: https://www.lsjlt.com/news/200556.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • java通过MySQL驱动拦截器实现执行sql耗时计算
    目录背景具体实现MySQL5MySQL6MySQL8使用方法测试结果背景 公司的一个需求,公司既有的链路追踪日志组件要支持MySQL的sql执行时间打印,要实现链路追踪常用的手段就是...
    99+
    2023-03-20
    java sql耗时计算 MySQL驱动拦截器耗时计算
  • java怎么通过MySQL驱动拦截器实现执行sql耗时计算
    这篇文章主要介绍了java怎么通过MySQL驱动拦截器实现执行sql耗时计算的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇java怎么通过MySQL驱动拦截器实现执行sql耗时计算文章都会有所收获,下面我们一起...
    99+
    2023-07-05
  • Java通过动态代理实现一个简单的拦截器操作
    一、代理 在使用动态代理实现拦截器之前我们先简单了解一下什么Java的代理。 代理,顾名思义,就是不直接操作被代理(下面都用目标对象称呼,听起来舒服一些)对象,而是通过一个代理对象去...
    99+
    2024-04-02
  • Java怎么通过动态代理实现一个简单的拦截器操作
    本文小编为大家详细介绍“Java怎么通过动态代理实现一个简单的拦截器操作”,内容详细,步骤清晰,细节处理妥当,希望这篇“Java怎么通过动态代理实现一个简单的拦截器操作”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧...
    99+
    2023-06-17
  • Java如何通过动态代理实现一个简单的拦截器操作
    这篇文章主要介绍“Java如何通过动态代理实现一个简单的拦截器操作”,在日常操作中,相信很多人在Java如何通过动态代理实现一个简单的拦截器操作问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Java如何通过动...
    99+
    2023-06-20
  • Java操作MyBatis-Plus通过自定义拦截器对mysql字段以注解形式实现自动加解密
    一.需求背景 跟大学室友闲谈时,了解到他公司正在做项目内对数据库敏感字段实现自动加解密的需求,使用的技术是Springboot,Mybatis-Plus,MySql等技术栈,加密算法是用的AES,密钥是放在华为云,这里实现一个阉割版的dem...
    99+
    2023-09-06
    mybatis mysql java
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作