2014-10-09 3 views
1

우리는 우리가 어떤 연결 누수를했고, 우리가 그들을 정정 생각했습니다 톰캣 연결 풀 및 유휴 연결

  • PostgreSQL의 9.2
    • 톰캣 7
    • JDBC를 사용하여 웹 사이트를 개발하고있다 (데이터베이스는 더 이상 응답을하지 않습니다), context.xml에 설정된 maxIdle보다 많은 유휴 연결이 있으므로 연결 풀의 동작이 계속 누출되는 것처럼 보입니다. 문제가 해결되었는지 확인하고 싶습니다.

      <Resource 
          auth="Container" 
          name="jdbc/postgres" 
          factory="org.apache.tomcat.jdbc.pool.DataSourceFactory" 
          type="javax.sql.DataSource" 
      
          username="admin" 
          password="..." 
      
          driverClassName="org.postgresql.Driver" 
          url="jdbc:postgresql://127.0.0.1:5432/..." 
          initialSize="1" 
          maxActive="50" 
          minIdle="0" 
          maxIdle="3" 
          maxWait="-1" 
          minEvictableIdleTimeMillis="1000" 
          timeBetweenEvictionRunsMillis="1000" 
          /> 
      

      만약 내가 제대로 이해하고, 우리가 1 개 대기 시작에 연결하고 오른쪽 부하에 따라 3-0에서이 있어야합니다 테스트 목적

      이, 나는 다음의 context.xml을 사용하고 있습니다?

      시작시 연결 1 개, 부하가 적 으면 최대 3 개 유휴 연결, 부하가 높으면 3 개 이상 유휴 연결. 그런 다음 이러한 연결은 즉시 닫히지 않으며 닫히는시기는 언제인지 (때로는 일부가 닫힌 경우) 알 수 없습니다.

      그래서 질문입니다.이 동작이 정상적인가요? 당신의 도움이

      편집에 대한

      감사 : removeAbandoned & removeAbandonedTimeout가 유휴 CONNEXIONS마다 removeAbandonedTimeout 폐쇄하게 사용 : 추가 팩토리 속성은 문제

      편집 2을 변경하지 않았다. 그래서 우리는 여전히 연결 누수가 남아 있습니다.

      public class PostgreSQLConnectionProvider { 
      
          public static Connection getConnection() throws NamingException, SQLException { 
      
           String dsString = "java:/comp/env/jdbc/postgres"; 
           Context context = new InitialContext(); 
           DataSource ds = (DataSource) context.lookup(dsString); 
           Connection connection = ds.getConnection(); 
      
           return connection; 
          } 
      } 
      

      DAO 추상 클래스 : 연결을 제공하기 위해

      PostgreSQLConnectionProvider, 단지 정적 클래스 : 여기에 우리가 데이터베이스에 연결하고 요청을 실행하는 데 사용하는 코드의 일부 조각은 :

      public abstract class DAO implements java.lang.AutoCloseable { 
      
          // Private attributes : 
          private Connection _connection; 
      
          // Constructors : 
          public DAO() { 
      
           try { _connection = PostgreSQLConnectionProvider.getConnection(); } 
           catch (NamingException | SQLException ex) { 
            Logger.getLogger(DAO.class.getName()).log(Level.SEVERE, null, ex); 
           } 
          } 
      
          // Getters : 
          public Connection getConnection() { return _connection; } 
      
          // Closeable : 
          @Override 
          public void close() throws SQLException { 
      
           if(!_connection.getAutoCommit()) { 
      
            _connection.rollback(); 
            _connection.setAutoCommit(true); 
           } 
      
           _connection.close(); 
          } 
      } 
      

      UserDAO, 작은 DAO 서브 클래스 (우리는 데이터베이스를 요청하는 몇 가지 DAO의 서브 클래스를가) 다음 살펴보면

      try(UserDAO dao = new UserDAO()) { 
      
          try { 
      
           User user = dao.getUserWithId(52); 
          } 
          catch (SQLException ex) { 
      
           // Handle exeption during getUserWithId 
          } 
      } 
      catch (SQLException ex) { 
      
          // Handle exeption during dao.close() 
      } 
      
    +0

    tomcat의 연결 풀 구현을 사용해보십시오. 풍부한 기능을 갖추고 있으며 좋은 문서가 있습니다. https://people.apache.org/~fhanik/jdbc-pool/jdbc-pool.html –

    +0

    감사합니다. 내가하고있는 일 (context.xml에서 사용중인 매개 변수를 볼 수있다). –

    +0

    주요 부분을 볼 수 없습니다 -'factory' 속성과 적절한 클래스 이름 –

    답변

    1

    :

    public class UserDAO extends DAO { 
    
        public User getUserWithId(int id) throws SQLException { 
    
         PreparedStatement ps = null; 
         ResultSet rs = null; 
    
         User user = null; 
    
         try { 
    
          String sql = "select * from \"USER\" where id_user = ?;"; 
    
          ps = getConnection().prepareStatement(sql); 
          ps.setInt(1, id); 
    
          rs = ps.executeQuery(); 
          rs.next(); 
    
          String login = rs.getString("login"); 
          String password = rs.getString("password"); 
          String firstName = rs.getString("first_name"); 
          String lastName = rs.getString("last_name"); 
          String email = rs.getString("email"); 
    
          user = new User(id, login, password, firstName, lastName, email); 
         } 
         finally { 
    
          if(rs != null) rs.close(); 
          if(ps != null) ps.close(); 
         } 
    
         return user; 
        } 
    } 
    

    DAO를 서브 클래스의 사용 예 코드는 DAO의 평생 동안 연결이 잡혀있는 것으로 보입니다. 평소 기대치 인 진술의 수명이 아닙니다. 일반적으로 문을 실행하려고하는 것처럼 풀에서 연결을 가져온 다음 풀에 반환하기 위해 완료되면 close()를 호출합니다.

    또한 finally 절에서 rs.close()ps.close()은 예외를 throw하여 준비된 문에 대한 마지막 호출이 누락 될 수 있습니다.

    Java 7에서는 준비된 명령문과 연결을 모두 닫을 try with resources 문을 사용할 수도 있습니다. 사양에 따르면 운전자는 진술 문을 닫을 때 결과를 닫아야합니다.

    +0

    답해 주셔서 감사합니다. 예, DAO의 수명 동안 연결이 잡혀 있지만, DAO는 몇 줄 뒤에 닫히고, 문제는 아닌 것 같군요, 그렇죠? 당신 말이 맞아요. 예외를 던질 수있는 close() 메소드를 try-catch (나는 드라이버의 구현에 의존하는 대신 rs.close() 메소드를 호출하는 것을 선호한다.) 다음 주까지 테스트 할 수 없다. close() 포장이 무언가를 변경했는지 알 수 있습니다. –

    +0

    getUserWithId()를 호출 할 때마다 DAO를 인스턴스화 한 다음 yes로 설정하면 문제가 없습니다. –