2017-06-15 84 views
0

我遇到了與使用HikariCP與解包的連接的資源泄漏問題。稍後解釋一下代碼。HikariCP連接泄漏使用解包的oracle.jdbc.driver.T4CConnection

我必須使用unwrapped連接來訪問oracle.sql.BFILE的Oracle方法。這是從Oracle目錄中流出一個二進制文件。

DataSource的實施例:

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的兩個單獨的類都是Leaking,而另一個不使用BFILE但使用Unwrapped Connection來使用OracleCallableStatement的方法也是泄漏。我已經實例化3個DataSources來按類型/函數拆分所有連接器,Leaks是使用Datasource.getConnection()。unwrap(oracle.jdbc.driver.OracleConnection.class)作爲其連接器的唯一池。

我是否在解開連接時出錯?爲什麼這是唯一一個泄漏?這是一個已知的驅動程序錯誤? (我還沒有拿出任何文章)BFILE似乎不是很受歡迎...

回答

1

你在做什麼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 
} 
+0

這個答案是正確的。 – brettw

+0

非常感謝!這是有道理的。我認爲關閉解包將釋放對池塘連接的引用,它應該至少是GC'd。現在我看到它在哪裏,補丁的方式:) – JustinL