Mybatis统计sql运行时间的两种方式

 更新时间:2024年11月04日 11:03:28   作者:知楠行易  
这篇文章主要介绍了Mybatis统计sql运行时间的方案,Spring Boot + Mybatis web项目,统计sql运行时间,用于分析慢sql,优化系统速度,方案有两种:自定义实现 Interceptor和使用现有依赖库(Druid),文中通过代码示例讲解的非常详细,需要的朋友可以参考下

需求:

Spring Boot + Mybatis web项目,统计sql运行时间,用于分析慢sql,优化系统速度。

方案有两种:

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

一、Mybatis 原生拦截器

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

  • 自定义拦截器,示例:
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) {
        // 可以通过配置文件传递参数到拦截器
    }
}

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

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

二、使用 Druid进行监控

2.1 Druid

  • 添加依赖:
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid</artifactId>
    <version>1.2.8</version> <!-- 使用最新的版本号 -->
</dependency>
  • 配置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
  • 启用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;
    }
}
  • 访问Druid监控页面:启动应用后,可以在浏览器访问 http://localhost:8080/druid(默认端口为8080),登录后查看SQL执行情况、慢SQL等详细信息。

2.2 druid-spring-boot-starter

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

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

  • 配置数据源和监控信息
########### 监控配置
# 是否启用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
  • 日志配置
 <!--   慢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>

以上就是Mybatis统计sql运行时间的两种方式的详细内容,更多关于Mybatis统计sql运行时间的资料请关注脚本之家其它相关文章!

相关文章

  • IDEA反编译jar,查看源码方式

    IDEA反编译jar,查看源码方式

    该篇文章总结了查看Java本地jar包注释的几种方法,包括使用快捷键CTRL+q和在设置中设置自动浮现注释
    2024-11-11
  • Spring Boot 项目中 JPA 语法的基本使用方法

    Spring Boot 项目中 JPA 语法的基本使用方法

    这篇文章主要介绍了 Spring Boot 项目中 JPA 语法的基本使用方法,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2023-10-10
  • Shrio框架实现自定义密码校验规则详解

    Shrio框架实现自定义密码校验规则详解

    文章主要介绍了Shiro框架的密码校验机制,包括内置的校验规则和自定义校验规则的实现,在Shiro中,密码校验主要通过自定义Realm来实现,具体步骤包括定义用户认证信息和权限信息,并在CredentialsMatcher中实现用户信息校验对比
    2026-03-03
  • java实现水仙花数的计算

    java实现水仙花数的计算

    这篇文章主要为大家详细介绍了java实现水仙花数的计算,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2019-08-08
  • java中@SuppressWarnings注解用法详解

    java中@SuppressWarnings注解用法详解

    这篇文章主要介绍了java中@SuppressWarnings注解用法详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-02-02
  • java中日期格式化的大坑

    java中日期格式化的大坑

    这篇文章主要介绍了java中日期格式化的大坑,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-01-01
  • springmvc html资源请求404的问题解决并分析

    springmvc html资源请求404的问题解决并分析

    这篇文章主要介绍了springmvc html资源请求404的问题解决并分析,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2023-09-09
  • Java实现爬虫给App提供数据(Jsoup 网络爬虫)

    Java实现爬虫给App提供数据(Jsoup 网络爬虫)

    这篇文章主要介绍了Java实现爬虫给App提供数据,即Jsoup 网络爬虫,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2016-01-01
  • Spring的三级缓存解决循环依赖问题

    Spring的三级缓存解决循环依赖问题

    这篇文章主要介绍了Spring的三级缓存解决循环依赖问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2025-06-06
  • Spring AOP注解配置与XML配置双实战教程

    Spring AOP注解配置与XML配置双实战教程

    本文详细介绍了面向切面编程(AOP)的概念、快速入门、核心概念、切点确定、通知分类、获取被增强方法相关信息、应用案例、XML配置、多切面顺序问题以及AOP原理中的动态代理,通过实例展示了如何在Spring框架中使用AOP进行方法增强,感兴趣的朋跟随小编一起看看吧
    2025-11-11

最新评论