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

Spring Boot应用Hikari连接池调试:如何获取连接唯一标识?

解决Hikari连接池连接标识打印及并发连接关闭问题

一、调试时连接哈希码与启动日志不一致的原因

Hikari连接池会对原始数据库连接(如PgConnection)做代理包装,生成HikariProxyConnection对象。你调试时拿到的是这个代理实例,而启动日志输出的是原始数据库连接的哈希码,因此两者无法匹配。

二、获取原始连接并打印一致标识

要拿到和启动日志一致的连接标识,需从代理对象中剥离出真实的数据库连接,以下是两种可行方案:

方案1:使用Hikari官方工具类(推荐)

Hikari提供com.zaxxer.hikari.util.HikariUnwrapper工具类,可直接获取原始连接,无需反射:

import com.zaxxer.hikari.util.HikariUnwrapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.jdbc.datasource.DelegatingDataSource;

import java.sql.Connection;
import java.sql.SQLException;

public class LoggingDelegatingDataSource extends DelegatingDataSource {
    private static final Logger log = LoggerFactory.getLogger(LoggingDelegatingDataSource.class);

    @Override
    public Connection getConnection() throws SQLException {
        Connection proxyConnection = super.getConnection();
        // 剥离出原始数据库连接
        Connection rawConnection = HikariUnwrapper.unwrap(proxyConnection);
        // 打印与启动日志一致的连接标识
        log.info("获取到连接,标识:{}", rawConnection);
        return proxyConnection;
    }

    @Override
    public Connection getConnection(String username, String password) throws SQLException {
        Connection proxyConnection = super.getConnection(username, password);
        Connection rawConnection = HikariUnwrapper.unwrap(proxyConnection);
        log.info("通过用户名密码获取到连接,标识:{}", rawConnection);
        return proxyConnection;
    }
}

方案2:反射获取原始连接(兼容旧版Hikari)

如果你的Hikari版本未提供HikariUnwrapper,可通过反射读取代理对象的delegate字段获取原始连接:

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.jdbc.datasource.DelegatingDataSource;

import java.lang.reflect.Field;
import java.sql.Connection;
import java.sql.SQLException;

public class LoggingDelegatingDataSource extends DelegatingDataSource {
    private static final Logger log = LoggerFactory.getLogger(LoggingDelegatingDataSource.class);

    @Override
    public Connection getConnection() throws SQLException {
        Connection proxyConnection = super.getConnection();
        Connection rawConnection = getRawConnection(proxyConnection);
        if (rawConnection != null) {
            log.info("获取到连接,标识:{}", rawConnection);
        }
        return proxyConnection;
    }

    private Connection getRawConnection(Connection proxy) {
        try {
            Field delegateField = proxy.getClass().getDeclaredField("delegate");
            delegateField.setAccessible(true);
            Object delegate = delegateField.get(proxy);
            // 递归处理多层代理(若存在)
            if (delegate instanceof Connection) {
                return getRawConnection((Connection) delegate);
            }
            return (Connection) delegate;
        } catch (NoSuchFieldException | IllegalAccessException e) {
            log.warn("无法获取原始连接,使用代理连接标识:{}", proxy);
            return proxy;
        }
    }
}

三、额外调试优化建议

  • 开启Hikari TRACE日志:在application.yml中配置,可输出连接的获取、归还、关闭全链路日志,追踪连接生命周期
    logging:
      level:
        com.zaxxer.hikari: TRACE
    
  • 关联线程信息:打印连接标识时加入当前线程ID和名称,方便定位并发场景下的线程交互
    log.info("线程[{}:{}]获取到连接,标识:{}", 
             Thread.currentThread().getId(), 
             Thread.currentThread().getName(), 
             rawConnection);
    
  • 增加归还日志:在重写的close方法(需包装Connection)中打印归还的连接标识,对比获取与归还的连接是否一致,排查异常关闭情况

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.17 07:37:13