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

Spring/Java应用中,监控DB到应用网络传输耗时的库或配置选项?

可行的自包含方案推荐

1. JDBC驱动拦截工具:P6Spy

P6Spy是一款JDBC代理驱动,可拦截所有JDBC调用,适合做细粒度计时。你可以通过自定义拦截器统计结果集读取阶段的耗时(这正是你要的网络传输+数据从DB到应用的时间):

  • 引入P6Spy依赖(根据Maven/Gradle等构建工具配置)
  • 配置spy.properties,指定自定义拦截器:
    driverlist=oracle.jdbc.OracleDriver
    statementInterceptor=com.yourpackage.ResultSetTimingInterceptor
    
  • 实现自定义拦截器,在查询执行完成后记录开始时间,在结果集关闭时计算耗时:
    public class ResultSetTimingInterceptor implements StatementInterceptor {
        private long startReadTime;
    
        @Override
        public void afterExecuteQuery(Statement statement, ResultSet resultSet, long timeElapsedNanos) {
            startReadTime = System.nanoTime();
        }
    
        @Override
        public void onResultSetClose(ResultSet resultSet) {
            long endTime = System.nanoTime();
            long readDurationMs = TimeUnit.NANOSECONDS.toMillis(endTime - startReadTime);
            System.out.printf("结果集读取(含网络传输)耗时:%dms%n", readDurationMs);
        }
    }
    
    这个时间区间正好对应你观察到的10秒暂停阶段——从Hibernate拿到JDBC结果集,到所有数据读取完成的耗时。

2. Hibernate事件监听器/自定义拦截器

利用Hibernate的扩展机制,拦截查询执行后的结果集处理流程:

  • 实现LoadEventListener或自定义Interceptor,在查询执行完成后开始计时,直到所有实体实例加载完成:
    public class ResultLoadTimingListener implements LoadEventListener {
        private long loadStartTime;
    
        @Override
        public void onLoad(LoadEvent event, LoadType loadType) throws HibernateException {
            if ((loadType == LoadType.GET || loadType == LoadType.LOAD) && loadStartTime == 0) {
                loadStartTime = System.nanoTime();
            }
        }
    
        public void onQueryComplete() {
            if (loadStartTime != 0) {
                long durationMs = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - loadStartTime);
                System.out.printf("实体加载(含网络传输)耗时:%dms%n", durationMs);
                loadStartTime = 0;
            }
        }
    }
    
  • 在Hibernate配置中注册该监听器,或通过Spring Boot的LocalContainerEntityManagerFactoryBean添加。

3. 自定义JDBC包装器

如果不想依赖第三方库,可自行实现JDBC的Statement和ResultSet包装类,统计结果集读取耗时:

  • 包装PreparedStatement,返回自定义ResultSet:
    public class TimingPreparedStatement extends DelegatingPreparedStatement {
        public TimingPreparedStatement(PreparedStatement delegate) {
            super(delegate);
        }
    
        @Override
        public ResultSet executeQuery() throws SQLException {
            ResultSet originalRs = super.executeQuery();
            return new TimingResultSet(originalRs);
        }
    }
    
  • 自定义ResultSet,在next()方法中累计读取时间:
    public class TimingResultSet extends DelegatingResultSet {
        private long totalReadTime = 0;
        private long lastStart;
    
        public TimingResultSet(ResultSet delegate) {
            super(delegate);
        }
    
        @Override
        public boolean next() throws SQLException {
            lastStart = System.nanoTime();
            boolean result = super.next();
            if (result) {
                totalReadTime += System.nanoTime() - lastStart;
            } else {
                System.out.printf("总结果集读取耗时:%dms%n", TimeUnit.NANOSECONDS.toMillis(totalReadTime));
            }
            return result;
        }
    }
    
  • 通过Spring的DataSource包装器注入自定义Statement。

这些方案均为自包含实现,无需依赖Wireshark等外部工具,可精准统计你需要的网络传输+数据读取阶段耗时。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 05:11:11