Skip to content

P42 怎么记录 MyBatis 的 SQL 耗时时间 ​

面试题:项目里怎么监控 MyBatis 每一条 SQL 的执行耗时?

方案一:MyBatis 拦截器(Interceptor,推荐) ​

MyBatis 的插件机制可以拦截四大对象的方法:

  • Executor(执行器:update/query/commit)
  • StatementHandler(SQL 语句处理)
  • ParameterHandler(参数)
  • ResultSetHandler(结果集)

统计耗时通常拦截 Executor.query/update:

java
@Intercepts({
    @Signature(type = Executor.class, method = "query",
        args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}),
    @Signature(type = Executor.class, method = "update",
        args = {MappedStatement.class, Object.class})
})
public class SqlCostInterceptor implements Interceptor {
    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        long start = System.currentTimeMillis();
        try {
            return invocation.proceed();
        } finally {
            long cost = System.currentTimeMillis() - start;
            MappedStatement ms = (MappedStatement) invocation.getArgs()[0];
            String sql = ms.getBoundSql(invocation.getArgs()[1]).getSql();
            log.info("SQL 耗时 {}ms: {}", cost, sql);
        }
    }
}

配置进 MyBatis:

yaml
mybatis:
  configuration:
    # 或在配置类里 mybatis-plus 用 @Bean Interceptor

扩展:能拿到 Mapper 方法 ID(ms.getId())、参数,可做慢 SQL 告警(超阈值记录/通知)。

方案二:MyBatis-Plus 内置性能分析插件 ​

MyBatis-Plus 提供 PerformanceInterceptor(旧版)/ MybatisPlusInterceptor,能输出每条 SQL 及耗时,开发环境用:

java
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
    MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
    interceptor.addInnerInterceptor(new PerformanceInterceptor()); // 旧版本
    return interceptor;
}

注意:性能分析插件有开销,生产慎用,可做成开关。

方案三:数据库层慢查询日志 ​

  • MySQL 开 slow_query_log,long_query_time 设置阈值;
  • 从数据库侧兜底发现慢 SQL(与业务代码解耦)。

方案四:APM 工具 ​

  • SkyWalking、Arthas(trace 命令)、Druid 监控(StatFilter 输出 SQL 统计)等,生产环境更常用。

加分点 ​

  • 拦截器原理:MyBatis 用 JDK 动态代理包装四大核心对象,插件就是代理链;
  • 只拦截慢的:先比较耗时再打日志,避免每条 SQL 都打日志影响性能;
  • 参数脱敏:日志里别把 SQL 参数原样打出来。

一句话总结 ​

自定义 MyBatis Interceptor 拦截 Executor 的 query/update,在 proceed() 前后记录耗时并输出 SQL/方法 ID,超过阈值告警;开发环境可用 MyBatis-Plus 性能插件,生产再配合 MySQL 慢查询日志和 APM。

基于 VitePress 重建