You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Spring Boot JPA+Hibernate中捕获单条SQL查询执行时长

解决方案:Spring Boot + JPA/Hibernate 捕获SQL/事务执行时长

方案1:Hibernate StatementInspector(推荐,支持单条SQL+时长捕获)

利用Hibernate原生的StatementInspector和StatementObserver,可以精准拦截每条SQL的执行时机,同时获取SQL语句和执行时长。

步骤1:实现SQL拦截器与计时器

import org.hibernate.resource.jdbc.spi.StatementInspector;
import java.sql.Statement;
import java.util.concurrent.ConcurrentHashMap;

public class TimingStatementInspector implements StatementInspector {
    private final ConcurrentHashMap<Statement, Long> startTimes = new ConcurrentHashMap<>();

    @Override
    public String inspect(String sql) {
        // 返回原始SQL,可在此处预处理SQL(比如脱敏)
        return sql;
    }

    // 记录Statement的执行开始时间
    public void recordStartTime(Statement statement) {
        startTimes.put(statement, System.currentTimeMillis());
    }

    // 计算并返回执行时长,同时清理记录
    public long calculateDuration(Statement statement) {
        Long startTime = startTimes.remove(statement);
        return startTime != null ? System.currentTimeMillis() - startTime : -1;
    }
}

步骤2:绑定Hibernate Statement执行监听

import org.hibernate.jpa.spi.JpaEntityManagerFactory;
import org.hibernate.resource.jdbc.spi.StatementObserver;
import jakarta.persistence.EntityManagerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Component;

@Component
public class HibernateTimingConfig implements InitializingBean {
    private final EntityManagerFactory entityManagerFactory;
    private final TimingStatementInspector inspector;

    public HibernateTimingConfig(EntityManagerFactory entityManagerFactory, TimingStatementInspector inspector) {
        this.entityManagerFactory = entityManagerFactory;
        this.inspector = inspector;
    }

    @Override
    public void afterPropertiesSet() {
        JpaEntityManagerFactory jpaEmf = (JpaEntityManagerFactory) entityManagerFactory;
        jpaEmf.getSessionFactory().getSessionFactoryOptions()
              .getServiceRegistry()
              .getService(org.hibernate.engine.jdbc.spi.JdbcServices.class)
              .getStatementPreparer()
              .addStatementObserver(new StatementObserver() {
                  @Override
                  public void statementPrepared(Statement statement) {
                      inspector.recordStartTime(statement);
                  }

                  @Override
                  public void statementExecuted(Statement statement, String sql) {
                      long duration = inspector.calculateDuration(statement);
                      // 此处可对接监控系统、日志系统或自定义业务逻辑
                      System.out.printf("SQL执行时长:%dms,语句:%s%n", duration, sql);
                  }
              });
    }
}

步骤3:配置启用Inspector

在application.yml中添加配置:

spring:
  jpa:
    properties:
      hibernate:
        session_factory:
          statement_inspector: com.yourpackage.TimingStatementInspector

方案2:Spring AOP 拦截Repository查询

如果不需要直接获取SQL,仅需统计Repository方法的执行时长,可使用AOP拦截Spring Data JPA的查询方法。

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
import org.springframework.util.StopWatch;

@Aspect
@Component
public class QueryTimingAspect {

    // 拦截自定义Repository下的所有查询类方法(find/query/get开头)
    @Around("execution(* com.yourpackage.repository.*.*(..)) && " +
            "(execution(* *find*(..)) || execution(* *query*(..)) || execution(* *get*(..)))")
    public Object measureQueryTime(ProceedingJoinPoint joinPoint) throws Throwable {
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        Object result = joinPoint.proceed();
        stopWatch.stop();

        long duration = stopWatch.getTotalTimeMillis();
        String methodName = joinPoint.getSignature().getName();
        System.out.printf("Repository方法[%s]执行时长:%dms%n", methodName, duration);

        return result;
    }
}

方案3:AOP拦截事务执行时长

若仅需要统计事务级别的执行时长,可直接拦截@Transactional注解的方法。

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
import org.springframework.util.StopWatch;

@Aspect
@Component
public class TransactionTimingAspect {

    @Around("@annotation(org.springframework.transaction.annotation.Transactional)")
    public Object measureTransactionTime(ProceedingJoinPoint joinPoint) throws Throwable {
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        Object result = joinPoint.proceed();
        stopWatch.stop();

        long duration = stopWatch.getTotalTimeMillis();
        String methodName = joinPoint.getSignature().getName();
        System.out.printf("事务方法[%s]执行时长:%dms%n", methodName, duration);

        return result;
    }
}

内容的提问来源于stack exchange,提问作者Twisted Tea

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.19 07:45:12