簡體   English   中英

使用解包的oracle.jdbc.driver.T4CConnection的HikariCP連接泄漏

[英]HikariCP Connection Leak using unwrapped oracle.jdbc.driver.T4CConnection

我在使用帶未連接的HikariCP時發生資源泄漏問題。 稍微解釋一下代碼。

我必須使用未包裝的連接來訪問oracle.sql.BFILE的Oracle方法。 這會將二進制文件從Oracle目錄中流式傳輸出來。

數據源示例:

private static DataSource unwrapDatasource;
public static synchronized DataSource getUnwrappedDataSource() {
    if (unwrapDatasource == null) {
        HikariConfig config = new HikariConfig();
        config.setMaximumPoolSize(50);
        config.setLeakDetectionThreshold(120000);
        config.setJdbcUrl(DATABASEURL);
        config.addDataSourceProperty("user", USERNAME);
        config.addDataSourceProperty("password", DBPASSWORD);
        config.addDataSourceProperty("driverType", "thin");
        config.setDriverClassName("oracle.jdbc.pool.OracleDataSource");
        config.setMaxLifetime(300000);
        config.setPoolName("UNWRAP");
        unwrapDatasource = new HikariDataSource(config);
    }

    return unwrapDatasource;
}

  public static Connection getUnwrappedConnection() {
    Connection con = null;
    try {
        con = this.getUnwrappedDataSource().getConnection().unwrap(oracle.jdbc.driver.OracleConnection.class);
    } catch (SQLException ex) {
        //logger junk ommitted for brevity
    }
    return con;
}

使用HikariCP-java7-2.4.12作為該應用程序非常老,並且在tomcat-6上運行。 這是被報告為泄漏的連接示例

    com.zaxxer.hikari.pool.ProxyLeakTask.run(poolProxyLeak.java:91) : <Connection leak detection triggered for {}, stack trace follows>
java.lang.Exception: Apparent connection leak detected
    at myapp.package.obfuscated.getUnwrapConnection(DataSourceConstants.java:253)
    at myapp.package.obfuscated.BB.execute(DatabaseCallingClass2.java:106)
    at myapp.package.obfuscated.BB.execute(DatabaseCallingClass2.java:85)
    at myapp.package.obfuscated.AA.execute(DataBaseCallingClass.java:52)
    at org.apache.struts.action.RequestProcessor.processActionPerform(RequestProcessor.java:425)
    at org.apache.struts.action.RequestProcessor.process(RequestProcessor.java:228)
    at org.apache.struts.action.ActionServlet.process(ActionServlet.java:1913)
    at org.apache.struts.action.ActionServlet.doPost(ActionServlet.java:462)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:643)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:723)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
    at org.displaytag.filter.ResponseOverrideFilter.doFilter(ResponseOverrideFilter.java:123)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:563)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:103)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:293)
    at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:859)
    at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:610)
    at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:503)
    at java.lang.Thread.run(Thread.java:745)

這是連接及其使用方式:

     Connection con = null;
     PreparedStatement pstmt = null;
     OracleResultSet rs = null;
     InputStream inputStream = null;
     StringBuilder stringBuilder = new StringBuilder(128);
     try {
            con = DataSourceConstants.getUnwrappedConnection();

            pstmt = con.prepareStatement("SELECT BFILENAME('ORACLE_DIR', 'fileDownload.12345') AS BFILE from dual" );  //hardcoded for example
            rs = (OracleResultSet) pstmt.executeQuery();

            rs.next();  //Assumption if rs.next() blows up, catch would grab it and resources would all attempt to close in finally block

            bfile = rs.getBFILE(1);
            bfile.open();
            inputStream = bfile.getBinaryStream();
            char c;
            long size = bfile.length();

            int i = 0;
            do {
                c= (char) inputStream.read();
                stringBuilder.append(c);
            } while (++i < size);

            } catch (Exception ex) {
              //logger ommitted but not throwing here
            } finally {
             //cleanup resources
             try { inputStream.close(); } catch (Exception ex) {}
             try { bfile.close(); } catch (Exception ex) {}
             try { rs.close(); } catch (Exception ex) {}
             try { pstmt.close(); } catch (Exception ex) {}
             try {con.close();  } catch (Exception ex){}
            }
       //use stringBuilder later in built output.

因此,上面檢索了一個未包裝的T4CConnection,以便我可以使用OracleResultSet和BFILE / getBFILE()。 這行得通,我得到了想要的結果,但是使用此結構檢索BFILE的兩個單獨的類都在泄漏,並且不使用BFILE但使用未包裝的連接來使用OracleCallableStatement的另一種方法也在泄漏。 我已實例化了3個DataSource,以按類型/功能拆分所有連接器,Leaks的唯一池是使用Datasource.getConnection()。unwrap(oracle.jdbc.driver.OracleConnection.class)作為其連接器的池。

展開的連接是否存在問題? 為什么這是唯一泄漏的? 這是已知的驅動程序錯誤嗎? (我還沒有寫任何文章)BFILE似乎不太受歡迎...

您在getUnwrappedConnection()中所做的不是您應該做的:如果要展開,則需要確保還保持連接池連接,因為關閉該連接會將其返回到池中。 因此,首先從池中獲得連接,然后僅在真正需要的時候解開連接,然后在完成后關閉從數據源獲得的原始連接。

不要關閉展開連接,因為這將關閉實際的物理連接,這將破壞使用連接池的目的。

簡而言之:

try (Connection connection = dataSource.getConnection()) {
    OracleConnection unwrapped = connection.unwrap(oracle.jdbc.driver.OracleConnection.class)

    ...

    // Do not close (or use try-with-resources) on unwrapped
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM