2017-09-05 5 views
0

이 JDBC 코드가 구현되었으며 주말에 연결이 누출되어 데이터베이스 기능이 작동하지 않는 문제가있었습니다. 문제가 무엇인지 확신 할 수는 없지만 스택 오버플로 커뮤니티에서이 코드를 실제로 누수가 발생하는지 확인하기 위해 전달하려고했습니다. 자원으로 시도해보십시오. 그러나 아마도 나는 뭔가를 놓쳤습니다. 모든 도움을 주셨습니다. 이 코드의 일부 예외가 연결 누출 생성 할 수있는 작은 가능성이 있다고 생각이 JDBC 코드가 유출되기 쉬운가요?

public ArrayList<LinkedHashMap> runReportQuery(final DataSource dataSource, final String asms, final String country) {  

     final ArrayList<LinkedHashMap> reportList = new ArrayList<>(); 

     this.executeQuery(dataSource, "select * from table where id =5", "customerReportType", true, reportList); 


      return reportList; 
     } 
     private void executeQuery(final DataSource queryDataSource, final String sql, final String reportType, 
            final Boolean isMarketSpecific, final ArrayList<LinkedHashMap> reportList){ 

      try(Connection conn = queryDataSource.getConnection(); 
       PreparedStatement ps = this.createPreparedStatement(conn, isMarketSpecific, sql); 
       ResultSet rs = ps.executeQuery(); 
      ) { 
       while(rs.next()){ 
        final LinkedHashMap<String, String> reportMap = new LinkedHashMap<>(); 
        //Creating report string that adds columns and respective values to report - This way we do not need to deal with DTO object creation logic 
        String reportString= ""; 
        //Iterate through each column, add column and respective data. 
        for (int i = 1; i <= rs.getMetaData().getColumnCount(); i++) 
         reportString = reportString + rs.getMetaData().getColumnLabel(i) + ": " + rs.getString(i) +"!$"; 
        reportMap.put("reportItem", reportType + "!$"+ reportString); 
        reportList.add(reportMap); 
       } 
      } 
      catch (final SQLException e){ 
       LOG.info("SqlException Occured", e); 
       e.printStackTrace(); 
       throw new RuntimeException(e); 
      } 
     } 

     private PreparedStatement createPreparedStatement(final Connection con, final boolean isMarketSpecific, final String sql) throws SQLException { 
      final PreparedStatement statement = con.prepareStatement(sql); 
      if(isMarketSpecific) 
      { 
       statement.setString(1, this.asms); 
       statement.setString(2, this.country); 
      } 
      return statement; 
     } 
+3

연결, 문 및 결과 집합을 닫습니다. 나에게 잘 어울려 ... – f1sh

+1

우리는 MySQL/MariaDB 인스턴스에 대해 이야기하고 있습니까? '예'이면 원하는 DB 클라이언트를 열고'show full processlist'를 실행하십시오 (지금 당장 실행하십시오 ;-). 그러면 열려있는 모든 연결 (적어도 해당 권한을 가진 사용자를 사용하는 경우), 연결되는 곳과 현재 진행중인 작업이 표시됩니다. 연결이 어디에서 시작하는지 조사의 출발점으로 행동해야합니다. – Lothar

+0

'for (int i = 1; i <= rs.getMetaData(). getColumnCount(); i ++)'루프에서 concat 문자열을 피하는 것이 좋습니다. 대신 StringBuilder를 사용하십시오. – StanislavL

답변

3

다음 PreparedStatement으로

if(isMarketSpecific) 
{ 
     statement.setString(1, this.asms); 
     statement.setString(2, this.country); 
} 

이미 얻을 수 있지만, ps에 할당되었는지는, 그것은하지 않습니다 try-with-resources로 닫을 수 있습니다. 일부 드라이버는 connection.close()에있는 모든 종속 리소스를 닫지 만 다른 리소스에서는 각 리소스를 명시 적으로 close() 개 필요합니다. 이러한 드라이버는 누출 될 수 있습니다.

1

@ gpeche의 진단에 동의합니다. 다음과 같이 수정할 수 있습니다.

private PreparedStatement createPreparedStatement(final Connection con, 
      final boolean isMarketSpecific, final String sql) 
      throws SQLException { 
    final PreparedStatement statement = con.prepareStatement(sql); 
    try { 
     if (isMarketSpecific) { 
      statement.setString(1, this.asms); 
      statement.setString(2, this.country); 
     } 
     return statement; 
    } catch (SQLException | RuntimeException | Error e) { 
     try { 
      statement.close(); 
     catch (SQLException e) { 
      // squash 
     } 
     throw e; 
    } 
} 

하지만 알 수 있듯이 이는 매우 장황합니다. 그래서 더 나은 해결책은 중첩 된 try-with-resource 문을 사용하기 위해 executeQuery을 재구성하는 것입니다. 예 :

try (Connection conn = queryDataSource.getConnection(); 
    PreparedStatement ps = con.prepareStatement(sql)) { 
    if (isMarketSpecific) { // This could be a separate method ... 
     statement.setString(1, this.asms); 
     statement.setString(2, this.country); 
    } 
    try (ResultSet rs = ps.executeQuery()) { 
     while(rs.next()){ 
      // etc 
     } 
    } 
} 
catch (final SQLException e){ 
    // etc 
}