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

OpenTracing+Spring事务中JDBC连接提前关闭的问题及方案咨询

解决方案:修复OpenTracing JDBC连接在事务中的比较问题

针对你遇到的NamedParameterJdbcTemplate#queryForStream在事务中导致连接比较不一致的问题,以下是几个可行的解决方案:

方案一:自定义TracingConnection与TracingPreparedStatement,修正getConnection()返回值

问题核心在于TracingConnection创建的PreparedStatement调用getConnection()时返回的是原始的Hikari代理连接,而非TracingConnection实例。通过自定义包装类,让PreparedStatement返回TracingConnection,保证与ConnectionHolder中的连接实例一致:

1. 自定义TracingConnection,重写prepareStatement方法

public class CustomTracingConnection extends TracingConnection {
    public CustomTracingConnection(Connection connection, String dbType, Tracer tracer) {
        super(connection, dbType, tracer);
    }

    @Override
    public PreparedStatement prepareStatement(String sql) throws SQLException {
        PreparedStatement delegate = super.prepareStatement(sql);
        return new CustomTracingPreparedStatement(delegate, this, getDbType(), getTracer());
    }

    // 按需重写其他prepareStatement重载方法(如带参数、返回生成键的版本)
}

2. 自定义TracingPreparedStatement,重写getConnection()

public class CustomTracingPreparedStatement extends TracingPreparedStatement {
    private final CustomTracingConnection tracingConnection;

    public CustomTracingPreparedStatement(PreparedStatement delegate, CustomTracingConnection tracingConnection, String dbType, Tracer tracer) {
        super(delegate, tracingConnection.getDelegate(), dbType, tracer);
        this.tracingConnection = tracingConnection;
    }

    @Override
    public Connection getConnection() throws SQLException {
        // 返回TracingConnection实例而非原始连接
        return tracingConnection;
    }
}

3. 自定义TracingDataSource,使用自定义连接包装类

public class CustomTracingDataSource extends TracingDataSource {
    public CustomTracingDataSource(DataSource dataSource, String dbType, Tracer tracer) {
        super(dataSource, dbType, tracer);
    }

    @Override
    protected Connection decorateConnection(Connection connection) {
        return new CustomTracingConnection(connection, getDbType(), getTracer());
    }
}

4. Spring配置中替换数据源

将原有Hikari数据源包装为自定义的CustomTracingDataSource,确保所有获取的连接都是自定义包装实例:

@Bean
public DataSource dataSource(Tracer tracer) {
    HikariDataSource hikariDs = new HikariDataSource();
    // 配置Hikari连接参数(URL、用户名、密码等)
    return new CustomTracingDataSource(hikariDs, "postgresql", tracer);
}

方案二:重写TracingConnection的equals/hashCode方法,基于原始连接比较

如果不想修改PreparedStatement的逻辑,可以让TracingConnection在比较时基于unwrap后的原始连接判断,这样即使传入的是Hikari代理连接,只要原始连接一致就会被判定为相等:

public class CustomTracingConnection extends TracingConnection {
    // 构造方法同方案一

    @Override
    public boolean equals(Object obj) {
        if (this == obj) return true;
        if (!(obj instanceof Connection)) return false;

        try {
            Connection thisRawConn = this.unwrap(Connection.class);
            Connection otherRawConn = ((Connection) obj).unwrap(Connection.class);
            return thisRawConn.equals(otherRawConn);
        } catch (SQLException e) {
            // 异常时 fallback到默认实例比较
            return super.equals(obj);
        }
    }

    @Override
    public int hashCode() {
        try {
            return this.unwrap(Connection.class).hashCode();
        } catch (SQLException e) {
            return super.hashCode();
        }
    }
}

这个方案不需要修改PreparedStatement,直接让DataSourceUtils.connectionEquals通过equals方法判断连接是否一致。

方案三:升级opentracing-contrib-jdbc版本

检查当前使用的opentracing-contrib-jdbc版本,部分旧版本存在PreparedStatement.getConnection()返回原始连接的bug。尝试升级到最新稳定版(如0.2.0及以上),看是否已修复该问题,无需自定义代码即可解决。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 23:15:03