Mybatis 统计sql运行时间

news2024/11/5 23:43:21

需求:
Spring Boot + Mybatis web项目,统计sql运行时间,用于分析慢sql,优化系统速度。
方案有两种:

  • 自定义实现 Interceptor ,更加灵活。
  • 使用现有依赖库(Druid):优点是简单好上手,但是统计的只有sql 信息 没有调用参数信息。

一、 Mybatis 原生拦截器

在 MyBatis 中记录 SQL 查询的执行时间和 SQL 语句,可以使用 MyBatis 的拦截器(Interceptor)。通过实现自定义拦截器,你可以捕获 SQL 执行的开始时间和结束时间,从而计算出执行时间,并将 SQL 语句记录到日志中。

  1. 自定义拦截器,示例:
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.logging.Log;
import org.apache.ibatis.logging.LogFactory;

import java.sql.Statement;
import java.util.Properties;

@Intercepts({
    @Signature(type = StatementHandler.class, method = "query", args = {Statement.class, ResultHandler.class}),
    @Signature(type = StatementHandler.class, method = "update", args = {Statement.class}),
    @Signature(type = StatementHandler.class, method = "batch", args = {Statement.class})
})
public class SqlExecutionInterceptor implements Interceptor {

    private static final Log logger = LogFactory.getLog(SqlExecutionInterceptor.class);

    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        // 获取 SQL 语句
        StatementHandler statementHandler = (StatementHandler) invocation.getTarget();
        BoundSql boundSql = statementHandler.getBoundSql();
        String sql = boundSql.getSql().replaceAll("\\s+", " ").trim();

        // 记录开始时间
        long startTime = System.currentTimeMillis();

        // 执行 SQL
        Object result = invocation.proceed();

        // 计算执行时间
        long endTime = System.currentTimeMillis();
        long executionTime = endTime - startTime;

        // 记录 SQL 语句和执行时间
        logger.info("SQL: " + sql);
        logger.info("Execution time: " + executionTime + " ms");

        return result;
    }

    @Override
    public Object plugin(Object target) {
        return Plugin.wrap(target, this);
    }

    @Override
    public void setProperties(Properties properties) {
        // 可以通过配置文件传递参数到拦截器
    }
}

  1. 注入Bean
@Configuration
public class MyBatisConfig {
    @Bean
    public SqlExecutionInterceptor sqlExecutionInterceptor() {
        return new SqlExecutionInterceptor();
    }
}

备注:可以结合logback等配置将日志打印到单独的日志文件中。

二、使用 Druid进行监控

2.1 Druid

  1. 添加依赖:
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid</artifactId>
    <version>1.2.8</version> <!-- 使用最新的版本号 -->
</dependency>
  1. 配置Druid数据源
spring:
  datasource:
    druid:
      url: jdbc:mysql://localhost:3306/your_database
      username: your_username
      password: your_password
      driver-class-name: com.mysql.cj.jdbc.Driver
      # 启用Druid监控功能
      filters: stat
      # 配置慢SQL记录
      maxActive: 20
      initialSize: 1
      minIdle: 1
      maxWait: 60000
      # 设置慢查询阈值,单位为毫秒
      slowSqlMillis: 2000
      logSlowSql: true
  1. 启用Druid监控Servlet和Filter
import com.alibaba.druid.support.http.WebStatFilter;
import com.alibaba.druid.support.http.StatViewServlet;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class DruidConfig {

    // 注册Druid的监控Servlet
    @Bean
    public ServletRegistrationBean<StatViewServlet> druidServlet() {
        ServletRegistrationBean<StatViewServlet> servletRegistrationBean = 
                new ServletRegistrationBean<>(new StatViewServlet(), "/druid/*");
        // 设置登录的用户名和密码
        servletRegistrationBean.addInitParameter("loginUsername", "admin");
        servletRegistrationBean.addInitParameter("loginPassword", "admin123");
        return servletRegistrationBean;
    }

    // 注册Druid的监控过滤器
    @Bean
    public FilterRegistrationBean<WebStatFilter> filterRegistrationBean() {
        FilterRegistrationBean<WebStatFilter> filterRegistrationBean = 
                new FilterRegistrationBean<>(new WebStatFilter());
        // 设置过滤的URL模式
        filterRegistrationBean.addUrlPatterns("/*");
        // 忽略的资源
        filterRegistrationBean.addInitParameter("exclusions", "*.js,*.css,/druid/*");
        return filterRegistrationBean;
    }
}
  1. 访问Druid监控页面:启动应用后,可以在浏览器访问 http://localhost:8080/druid(默认端口为8080),登录后查看SQL执行情况、慢SQL等详细信息。

2.2 druid-spring-boot-starter

就像 Spring Boot 和 Spring,阿里提供了 druid-spring-boot-starter 可以更加方便的基于配置启用相关 Filter。

  1. 添加依赖:
 <dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid-spring-boot-starter</artifactId>
    <version>1.2.8</version>
</dependency>

  1. 配置数据源和监控信息
########### 监控配置
# 是否启用StatFilter,默认值为false
spring.datasource.druid.web-stat-filter.enabled=true
# 设置监控拦截的url pattern,如果不配置默认所有请求都被拦截
spring.datasource.druid.web-stat-filter.url-pattern=/*
# 设置不拦截的url,多个用英文逗号分隔
spring.datasource.druid.web-stat-filter.exclusions=/druid/*
# 是否开启Session统计功能,默认值为true
spring.datasource.druid.web-stat-filter.session-stat-enable=true
# 设置Session统计的最大数量,-1表示不限制,默认值为1000
spring.datasource.druid.web-stat-filter.session-stat-max-count=1000
# 设置Session统计的Principal名称,默认值为“sessionStat”
spring.datasource.druid.web-stat-filter.principal-session-name=sessionStat
# 设置保存Session ID的cookie名称,默认值为“sessionStatMaxCount”
spring.datasource.druid.web-stat-filter.principal-cookie-name=sessionStatMaxCount
# 是否开启profile,如果开启,需要配置druid监控的filter:profile
spring.datasource.druid.web-stat-filter.profile-enable=true

######### StatViewServlet配置
# 是否启用StatViewServlet,默认值为false(考虑到安全问题默认并未启动,如需启用建议设置密码或白名单以保障安全)
spring.datasource.druid.stat-view-servlet.enabled=true
# 设置监控页面的访问路径,默认为/druid/*
spring.datasource.druid.stat-view-servlet.url-pattern=/druid/*
# 是否允许重置监控数据,默认值为true
spring.datasource.druid.stat-view-servlet.reset-enable=true
# 设置监控页面的登录用户名,默认为空(如果设置了登录用户名和密码,访问监控页面时会弹出登录框)
spring.datasource.druid.stat-view-servlet.login-username=admin
# 设置监控页面的登录密码,默认为空(如果设置了登录用户名和密码,访问监控页面时会弹出登录框)
spring.datasource.druid.stat-view-servlet.login-password=123456
# 设置允许访问监控页面的IP地址列表,多个IP地址之间用英文逗号分隔,默认为空(如果设置了白名单,只有在白名单内的IP地址才能访问监控页面)
spring.datasource.druid.stat-view-servlet.allow=127.0.0.1,192.168.1.1
# 设置禁止访问监控页面的IP地址列表,多个IP地址之间用英文逗号分隔,默认为空(如果设置了黑名单,黑名单内的IP地址不能访问监控页面)
spring.datasource.druid.stat-view-servlet.deny=192.168.1.2

#### 慢sql
# 开启 Druid 监控过滤器
spring.datasource.druid.filter.stat.enabled=true
# 是否记录慢 SQL 查询
spring.datasource.druid.filter.stat.log-slow-sql=true
# 数据库类型,这里是 MySQL
spring.datasource.druid.filter.stat.db-type=mysql
# 定义慢 SQL 查询的阈值,单位为毫秒
spring.datasource.druid.filter.stat.slow-sql-millis=1000
  1. 日志配置
 <!--   慢sql   -->
    <appender name="slowSqlLog" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <File>${log.path}/slow_sql-${log.env}.log</File>
        <!--滚动策略,按照时间滚动 TimeBasedRollingPolicy-->
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <!--文件路径,定义了日志的切分方式——把每一天的日志归档到一个文件中,以防止日志填满整个磁盘空间-->
            <FileNamePattern>${log.path}/arch/slow_sql/slow_sql.%d{yyyy-MM-dd}.%i.log.gz</FileNamePattern>
            <!-- 单个日志文件最多 100MB -->
            <maxFileSize>100MB</maxFileSize>
            <!--只保留最近10天的日志-->
            <maxHistory>10</maxHistory>
            <!--用来指定日志文件的上限大小,那么到了这个值,就会删除旧的日志-->
            <totalSizeCap>1GB</totalSizeCap>
        </rollingPolicy>
        <!--日志输出编码格式化-->
        <encoder>
            <charset>UTF-8</charset>
            <pattern>[%d{yyyy-MM-dd HH:mm:ss}|%mdc{traceId}|] - %msg%n</pattern>
        </encoder>
    </appender>

    <logger name="com.alibaba.druid.filter.stat.StatFilter" level="info" additivity="false">
        <appender-ref ref="slowSqlLog"/>
    </logger>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2233906.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

优化文本嵌入,大幅提升RAG检索速度

大家好&#xff0c;文本嵌入技术能够将文字信息转换成高维向量表示的数字&#xff0c;提供了一种理解和处理文本数据的新方式&#xff0c;帮助我们更好地理解和处理文本数据。这些向量能够捕捉文本的深层特征&#xff0c;进而支持多种应用&#xff0c;比如理解语义、进行文本分…

【Node技巧】Node.js创建REST架构风格的API

&#x1f9d1;‍&#x1f4bc; 一名茫茫大海中沉浮的小小程序员&#x1f36c; &#x1f449; 你的一键四连 (关注 点赞收藏评论)是我更新的最大动力❤️&#xff01; &#x1f4d1; 目录 &#x1f53d; 前言1️⃣ 什么是REST API&#xff1f;2️⃣ Node.js构建REST API的优势3️…

js中怎么把excel和pdf文件转换成图片打包下载

index.html <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>文件转图片工具</title><!-- 本…

Linux 练习三

1、建立用户组 shengcan&#xff0c;其id 为 2000 [rootlocalhost 桌面]# groupadd -g 2000 shengchan 2、建立用户组 caiwu&#xff0c;其id 为 2001 [rootlocalhost 桌面]# groupadd -g 2001 caiwu 3、建立用户组 jishu&#xff0c;其 id 为 2002 [rootlocalhost 桌面]#…

uniapp vue3 使用echarts-gl 绘画3d图表

我自己翻遍了网上&#xff0c;以及插件市场&#xff0c;其实并没有uniapp 上使用echarts-gl的样例&#xff0c;大多数都是使用插件市场的echarts的插件 开始自己尝试直接用echartsgl 没有成功&#xff0c;后来尝试使用threejs 但是也遇到一些问题&#xff0c;最后我看官网的时…

openGauss数据库-头歌实验1-4 数据库及表的创建

一、创建数据库 &#xff08;一&#xff09;任务描述 本关任务&#xff1a;创建指定数据库。 &#xff08;二&#xff09;相关知识 数据库其实就是可以存放大量数据的仓库&#xff0c;学习数据库我们就从创建一个数据库开始吧。 为了完成本关任务&#xff0c;你需要掌握&a…

Android TextView自动换行文本显示不全解决

某些情况下&#xff0c;TextView自动换行后&#xff0c;会出现每行结尾处显示不全的问题&#xff0c; 如图&#xff1a; 常见解决方案&#xff1a; 设置TextView的“ellipsize”属性为“end” 实测无效&#xff01;将TextView外部的Layout改为RelativeLayout 实测无效&…

华为 HarmonyOS NEXT 原生应用开发: 动画的基础使用(属性、显示、专场)动画

2024年11月5日 LiuJinTao 文章目录 鸿蒙中动画的使用一、属性动画 - animation属性动画代码示例 二、显示动画 - AnimateTo三、专场动画 鸿蒙中动画的使用 一、属性动画 - animation 属性动画代码示例 /*** 属性动画的演示*/ Entry Component struct Index {State selfWidth:…

信号与噪声分析——第三节:随机过程的统计特征

随机过程的定义&#xff1a; 随机过程是一种数学模型&#xff0c;用来描述系统或现象在时间或者空间上随之变化的不确定性。 一个随机过程的数字特征 1.数学期望&#xff08;统计平均值&#xff09;&#xff1a; 表示为 数学期望是随机过程在时间 t 上的平均值&#xff0c;通常…

Linux SSH免密登入以及配置脚本

一、ssh原理简单介绍 客户端生成一对公钥和私钥&#xff0c;并将自己的公钥发送到服务器上 其中公钥用来加密&#xff0c;私钥用来解密。 二、ssh免密登入实现步骤详解 我这就以服务器controller和客户端compute来做为例子 2.1、首先在controller上输入ssh-keygen -t rsa …

搜维尔科技:Manus VR数据手套-机器人手部数据采集,推动机器人技术新高度

人工智能机器人培训-构建集成 将实时数据直接传输到ROS并开始控制你的机器人。使用我们的 C Windows 和Linux SDK开发集成&#xff0c;以用于自定义管道。 原始数据&#xff1a;推动机器学习和机器人技术 以CSV格式记录并导出手指运动作为原始数据。为机器学习和机器人应用提…

将HTML项目上传至Gitee仓库(详细教程)

1.登录giett giett地址链接:Gitee - 基于 Git 的代码托管和研发协作平台 2.新建一个giett仓库 创建后得到远程仓库&#xff1a; 3、在本地项目文件夹右击鼠标点击 Open Git Bash Here 4、输入命令 命令:git init&#xff0c;这个目录变成git可以管理的仓库&#xff0c;会出…

重大917该如何复习?难度大不大?重点是啥?

C哥专业提供——计软考研院校选择分析专业课备考指南规划 重大917整体难度不高&#xff0c;认真研究好各年真题&#xff0c;经过系统扎实的复习&#xff0c;相信同学一定能取得好的成绩&#xff01; 添加图片注释&#xff0c;不超过 140 字&#xff08;可选&#xff09; 重庆…

CentOS 7 安装 ntp,自动校准系统时间

1、安装 ntp yum install ntp 安装好后&#xff0c;ntp 会自动注册成为服务&#xff0c;服务名称为 ntpd 2、查看当前 ntpd 服务的状态 systemctl status ntpd 3、启动 ntpd 服务、查看 ntpd 服务的状态 systemctl start ntpdsystemctl status ntpd 4、设置 ntpd 服务开机启…

信息安全工程师(77)常见网络安全应急事件场景与处理流程

前言 网络安全应急事件场景多样&#xff0c;处理流程也需根据具体情况灵活调整。以下将详述几种常见的网络安全应急事件场景及其处理流程。 一、数据泄露事件 场景描述&#xff1a; 数据泄露是指敏感、受保护或机密数据被未经授权的个人复制、传输、查看、窃取或使用。这种事件…

使用Django REST framework构建RESTful API

使用Django REST framework构建RESTful API Django REST framework简介 安装Django REST framework 创建Django项目 创建Django应用 配置Django项目 创建模型 迁移数据库 创建序列化器 创建视图 配置URL 配置全局URL 配置认证和权限 测试API 使用Postman测试API 分页 过滤和排序…

【保姆级教程】使用 oh-my-posh 和 clink 打造个性化 PowerShell 和 CMD

内容预览 ≧∀≦ゞ 终端美化指南—— oh-my-posh 和 clink 篇引言一、准备工作默认终端&#xff1a;Windows Terminal离线安装步骤 包管理器&#xff1a;scoop为什么选择使用 Scoop 安装&#xff1f;scoop 安装 字体下载 二、配置 Windows Terminal三、配置 oh-my-posh安装激活…

「Mac畅玩鸿蒙与硬件17」鸿蒙UI组件篇7 - Animation 组件基础

在应用开发中&#xff0c;动画效果可以增强用户体验。鸿蒙框架提供了 translate、scale 和 rotate 等动画功能&#xff0c;允许对组件进行平移、缩放和旋转等操作。本篇将介绍 Animation 组件的基础知识和示例代码。 关键词 Animation 组件动画效果位置动画自动动画缩放动画 一…

编写第一个 Appium 测试脚本:从安装到运行!

前言 最近接到一个测试项目&#xff0c;简单描述一下&#xff0c;需求就是&#xff1a;一端发送指令&#xff0c;另一端接受指令并处理指令。大概看了看有上百条指令&#xff0c;点点点岂不是废了&#xff0c;而且后期迭代&#xff0c;每次都需要点点点&#xff0c;想想就头大…

vue 使用docx-preview 预览替换文档内的特定变量

在开发合同管理中&#xff0c;需要使用到此功能&#xff0c;就是替换合同模板内的一些字符串&#xff0c;如&#xff1a;甲乙方名称&#xff0c;金额日期等&#xff0c;合同内容不变。效果如下&#xff1a; 使用docx-preview 好处是只预览不可编辑内容。 前端vue import { re…