通过MySQL驱动拦截器实现执行sql耗时计算
文章目录
- 背景
- 具体实现
- MySQL5
- MySQL6
- MySQL8
- 使用方法
- 测试结果
背景
公司的一个需求,公司既有的链路追踪日志组件要支持MySQL的sql执行时间打印,要实现链路追踪常用的手段就是实现第三方框架或工具提供的拦截器接口或者是过滤器接口,对于MySQL也不例外,实际上就是实现了MySQL驱动的拦截器接口而已。
具体实现
MySQL的渠道有不同的版本,不同版本的拦截器接口是不同的,所以要针对你所使用的不同版本的MySQL驱动去实现响应的拦截器,接下来分别介绍下MySQL渠道5,6,8版本的实现方式。
MySQL5
这里以MySQL渠道5.1.18版本为例实现,实现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 {@Overridepublic void init(Connection connection, Properties properties) throws SQLException {}@Overridepublic 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;}@Overridepublic boolean executeTopLevelOnly() {return false;}@Overridepublic void destroy() {}@Overridepublic 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 {@Overridepublic StatementInterceptor init(MysqlConnection mysqlConnection, Properties properties,Log log) {return null;}@Overridepublic <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;}@Overridepublic boolean executeTopLevelOnly() {return false;}@Overridepublic void destroy() {}@Overridepublic <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 {@Overridepublic QueryInterceptor init(MysqlConnection mysqlConnection, Properties properties, Log log) {return null;}@Overridepublic <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;}@Overridepublic boolean executeTopLevelOnly() {return false;}@Overridepublic void destroy() {}@Overridepublic <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
相关文章:
通过MySQL驱动拦截器实现执行sql耗时计算
文章目录背景具体实现MySQL5MySQL6MySQL8使用方法测试结果背景 公司的一个需求,公司既有的链路追踪日志组件要支持MySQL的sql执行时间打印,要实现链路追踪常用的手段就是实现第三方框架或工具提供的拦截器接口或者是过滤器接口,对于MySQL也不…...
易基因|独家分享:高通量测序后的下游实验验证方法——DNA甲基化篇
大家好,这里是专注表观组学十余年,领跑多组学科研服务的易基因。此前,我们分享了DNA甲基化研究的测序数据挖掘思路(点击查看详情),进而鉴定出研究的目的基因或目标区域的DNA甲基化。做完测序后,…...
java基础系列(七) 同步和异步理解
一. 问题描述 同步传输和异步传输是web和数据库的重要知识点,会被很多老师强调。那么,它们有什么相同点和不同点?它们对于我们学习编程的意义在哪里? 二. 概念 首先什么是同步和异步? 这里的同步是指&…...
吉林大学 程序设计基础 2022级 OJ期末考试 2.23
本人能力有限,发出只为帮助有需要的人。 以下为实验课的复盘,内容会有大量失真,请多多包涵。 1.双手剑士的最优搭配 每把剑有攻击力和防御力两个属性。双手剑士可以同时拿两把剑,其得到攻击力为两把剑中的攻击力的最大值&#…...
【项目实战】SpringMVC拦截器实战 - 自定义拦截器防止重复提交
一、背景说明 如何能够实现防止重复提交呢?以下是一种可选的方式。 二、代码实战 2.1 注册重复提交拦截器到SpringMVC中 @Configuration @AllArgsConstructor public class ResourcesConfig implements WebMvcConfigurer {private final RepeatSubmitInterceptor repeatSu…...
C++ STL:容器 Container
文章目录1、序列容器1.1、容器共性1.2、vectorvector 结构* vector 扩容原理* vector 迭代器失效1.3、dequedeque 结构deque 迭代器deque 模拟连续空间1.4、listlist 特殊操作list 结构list 迭代器2、关联式容器2.1、容器共性2.2、容器特性3、无序关联式容器3.1、容器共性3.2、…...
urllib之urlopen和urlretrieve的headers传入以及parse、urlparse、urlsplit的使用
urllib库是什么?urllib库python的一个最基本的网络请求库,不需要安装任何依赖库就可以导入使用。它可以模拟浏览器想目标服务器发起请求,并可以保存服务器返回的数据。urllib库的使用:1、request.urlopen(1)只能传入url的方式from http.clie…...
【C++】二叉搜索树的模拟实现
一、概念 二叉搜索树又称二叉排序树,它或者是一棵空树,或者是具有以下性质的二叉树: 若它的左子树不为空,则左子树上所有节点的值都小于根节点的值若它的右子树不为空,则右子树上所有节点的值都大于根节点的值它的左右子树也分别…...
HNU工训中心:元器件及测量基础实验报告
工训中心的牛马实验 1.实验目的 1.熟悉测量验证常用元器件参数、 并采用替代法(测量回路电流)测量其伏安特性的方法。 2.熟悉测量误差及减小测量误差注意事项 2.实验仪器和器材 1.实验仪器. 直流稳压电源型号:IT6302 台式多用表型号:UT805A 2.实验( 箱)器材 电路实验箱…...
博客系统--自动化测试
项目体验地址(账号:123,密码:123)http://120.53.20.213:8080/blog_system/login.html项目后端说明:http://t.csdn.cn/32Nnv项目码云Gitee地址:https://gitee.com/GoodManSS/project/tree/master…...
Day903.自增主键不能保证连续递增 -MySQL实战
自增主键不能保证连续递增 Hi,我是阿昌,今天学习记录的是关于自增主键不能保证连续递增的内容。 MySql保证了主键是自增,但不相对连续;帮助开发人员快速识别每个行的唯一性,并提高查询效率。 自增主键可以让主键索引…...
02-MyBatis查询-
文章目录Mybatis CRUD练习1,配置文件实现CRUD1.1 环境准备Debug01: 别名mybatisx报错1.2 查询所有数据1.2.1 编写接口方法1.2.2 编写SQL语句1.2.3 编写测试方法1.2.4 起别名解决上述问题1.2.5 使用resultMap解决上述问题1.2.6 小结1.3 查询详情1.3.1 编写接口方法1.…...
外盘国际期货招商:2023年3月关注日历,把握重要投资机会
2023年3月大事件日历 关注大事日历,把握重要投资机会 3月1日:马斯克推出特斯拉宏图第三篇章 3月1-2日:G20外长会议 3月4-5日:全国两会召开 3月9日:中国2月CPI、PPI数据 待定(前次进行日期:…...
Linux学习(9.1)文件系统的简单操作
以下内容转载自鸟哥的Linux私房菜 原文:鸟哥的 Linux 私房菜 -- Linux 磁盘与文件系统管理 (vbird.org) 磁盘与目录的容量 df:列出文件系统的整体磁盘使用量;du:评估文件系统的磁盘使用量(常用在推估目录所占容量) df du 实体…...
Hadoop综合案例 - 聊天软件数据
目录1、聊天软件数据分析案例需求2、基于Hive数仓实现需求开发2.1 建库2.2 建表2.3 加载数据2.4 ETL数据清洗2.5 需求指标统计---都很简单3、FineBI实现可视化报表3.1 FineBI介绍3.2 FineBI配置数据3.3 构建可视化报表1、聊天软件数据分析案例需求 MR速度慢—引入hive 背景&a…...
Python进阶-----面向对象1.0(对象和类的介绍、定义)
目录 前言: 面向过程和面向对象 类和对象 Python中类的定义 (1)类的定义形式 (2)深层剖析类对象 前言: 感谢各位的一路陪伴,我学习Python也有一个月了,在这一个月里我收获满满…...
天猫淘宝企业服务为中小微企业打造供应链智能协同网络,让采购不再将就!丨爱分析报告
编者按:近日天猫淘宝企业服务&爱分析联合发布《2023中小微企业电商采购白皮书》,为中小微企业采购数字化带来红利。 某水泵企业:线上客户主要是中小微企业,线上业绩遇到瓶颈,如何突破呢?某焊割设备企业…...
基于四信网络摄像机的工业自动化应用
方案背景 随着数控机床被广泛的应用在工业生产中,数控技术发展成为制造业的核心。 鉴于数控机床的复杂性,以及企业人力储备有限,设备的监控和维护必须借助外部力量,而如何实现车间实时监测成了目前迫切解决的问题。 方案需求 ①兼…...
软件测试2
一 web掐断三大核心技术 HTML:负责网页的结构 CSS:负责网页的美化 JS:负责网页的行为 二 工具的使用 改变HBuilder文字的大小: 工具-视觉主题设置-大小22-确定 三 html简介 中文定义:超文本标记语言 新建一个html…...
(二分查找)leetcode162. 寻找峰值
文章目录一、题目1、题目描述2、基础框架3、原题链接二、解题报告1、思路分析2、时间复杂度3、代码详解三、本题小知识一、题目 1、题目描述 峰值元素是指其值严格大于左右相邻值的元素。 给你一个整数数组 nums,找到峰值元素并返回其索引。数组可能包含多个峰值…...
KubeSphere 容器平台高可用:环境搭建与可视化操作指南
Linux_k8s篇 欢迎来到Linux的世界,看笔记好好学多敲多打,每个人都是大神! 题目:KubeSphere 容器平台高可用:环境搭建与可视化操作指南 版本号: 1.0,0 作者: 老王要学习 日期: 2025.06.05 适用环境: Ubuntu22 文档说…...
[ICLR 2022]How Much Can CLIP Benefit Vision-and-Language Tasks?
论文网址:pdf 英文是纯手打的!论文原文的summarizing and paraphrasing。可能会出现难以避免的拼写错误和语法错误,若有发现欢迎评论指正!文章偏向于笔记,谨慎食用 目录 1. 心得 2. 论文逐段精读 2.1. Abstract 2…...
EtherNet/IP转DeviceNet协议网关详解
一,设备主要功能 疆鸿智能JH-DVN-EIP本产品是自主研发的一款EtherNet/IP从站功能的通讯网关。该产品主要功能是连接DeviceNet总线和EtherNet/IP网络,本网关连接到EtherNet/IP总线中做为从站使用,连接到DeviceNet总线中做为从站使用。 在自动…...
自然语言处理——Transformer
自然语言处理——Transformer 自注意力机制多头注意力机制Transformer 虽然循环神经网络可以对具有序列特性的数据非常有效,它能挖掘数据中的时序信息以及语义信息,但是它有一个很大的缺陷——很难并行化。 我们可以考虑用CNN来替代RNN,但是…...
ArcGIS Pro制作水平横向图例+多级标注
今天介绍下载ArcGIS Pro中如何设置水平横向图例。 之前我们介绍了ArcGIS的横向图例制作:ArcGIS横向、多列图例、顺序重排、符号居中、批量更改图例符号等等(ArcGIS出图图例8大技巧),那这次我们看看ArcGIS Pro如何更加快捷的操作。…...
全面解析各类VPN技术:GRE、IPsec、L2TP、SSL与MPLS VPN对比
目录 引言 VPN技术概述 GRE VPN 3.1 GRE封装结构 3.2 GRE的应用场景 GRE over IPsec 4.1 GRE over IPsec封装结构 4.2 为什么使用GRE over IPsec? IPsec VPN 5.1 IPsec传输模式(Transport Mode) 5.2 IPsec隧道模式(Tunne…...
Java线上CPU飙高问题排查全指南
一、引言 在Java应用的线上运行环境中,CPU飙高是一个常见且棘手的性能问题。当系统出现CPU飙高时,通常会导致应用响应缓慢,甚至服务不可用,严重影响用户体验和业务运行。因此,掌握一套科学有效的CPU飙高问题排查方法&…...
CVE-2020-17519源码分析与漏洞复现(Flink 任意文件读取)
漏洞概览 漏洞名称:Apache Flink REST API 任意文件读取漏洞CVE编号:CVE-2020-17519CVSS评分:7.5影响版本:Apache Flink 1.11.0、1.11.1、1.11.2修复版本:≥ 1.11.3 或 ≥ 1.12.0漏洞类型:路径遍历&#x…...
MySQL 知识小结(一)
一、my.cnf配置详解 我们知道安装MySQL有两种方式来安装咱们的MySQL数据库,分别是二进制安装编译数据库或者使用三方yum来进行安装,第三方yum的安装相对于二进制压缩包的安装更快捷,但是文件存放起来数据比较冗余,用二进制能够更好管理咱们M…...
打手机检测算法AI智能分析网关V4守护公共/工业/医疗等多场景安全应用
一、方案背景 在现代生产与生活场景中,如工厂高危作业区、医院手术室、公共场景等,人员违规打手机的行为潜藏着巨大风险。传统依靠人工巡查的监管方式,存在效率低、覆盖面不足、判断主观性强等问题,难以满足对人员打手机行为精…...
