Java에서 데이터베이스 연결 닫기


121

조금 혼란 스러워요. http://en.wikipedia.org/wiki/Java_Database_Connectivity 에서 아래를 읽고있었습니다 .

Connection conn = DriverManager.getConnection(
     "jdbc:somejdbcvendor:other data needed by some jdbc vendor",
     "myLogin",
     "myPassword" );

Statement stmt = conn.createStatement();
try {
    stmt.executeUpdate( "INSERT INTO MyTable( name ) VALUES ( 'my name' ) " );
} finally {
    //It's important to close the statement when you are done with it
    stmt.close();
}

conn 연결을 닫을 필요가 없습니까? conn.close ()가 발생하지 않으면 실제로 무슨 일이 일어나고 있습니까?

현재 두 양식 중 하나를 닫지 않는 비공개 웹 앱이 있지만 중요한 것은 실제로 stmt 하나, conn 하나 또는 둘 다입니까?

사이트가 간헐적으로 다운되지만 서버는 데이터베이스 연결 문제라고 계속해서 말하고 있습니다. 제 의심은 닫히지 않았다는 것입니다.하지만 어느 쪽을 닫아야할지 모르겠습니다.


닫기를 처리하기 위해 다른 드라이버 및 템플릿에 의존하지 않고 직접 연결을 닫는 것이 항상 가장 좋은 방법입니다. 연결을 닫지 않으면 소켓과 리소스가 충돌 (더 이상 리소스 시나리오 없음) 또는 다시 시작될 때까지 영구적으로 열립니다.
Arun Joshla 19

답변:


196

사용이 끝나면 연결이 유지하고있을 수있는 다른 데이터베이스 리소스 (커서, 핸들 등)를 해제하기 위해 메서드를 Connection호출하여 명시 적으로 닫아야합니다 close().

사실, 자바의 안전 패턴은 당신이 종료하는 것입니다 ResultSet, Statement그리고 ConnectionA의 (순서대로) finally처럼, 블록 당신이 그들과 함께 할 때 뭔가를 :

Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;

try {
    // Do stuff
    ...

} catch (SQLException ex) {
    // Exception handling stuff
    ...
} finally {
    if (rs != null) {
        try {
            rs.close();
        } catch (SQLException e) { /* ignored */}
    }
    if (ps != null) {
        try {
            ps.close();
        } catch (SQLException e) { /* ignored */}
    }
    if (conn != null) {
        try {
            conn.close();
        } catch (SQLException e) { /* ignored */}
    }
}

finally블록 약간 (널 검사를 피하기 위해)으로 개선 될 수있다 :

} finally {
    try { rs.close(); } catch (Exception e) { /* ignored */ }
    try { ps.close(); } catch (Exception e) { /* ignored */ }
    try { conn.close(); } catch (Exception e) { /* ignored */ }
}

그러나 여전히 이것은 매우 장황하므로 일반적으로 도우미 클래스를 사용하여 null-safe 도우미 메서드에서 개체를 닫고 finally블록은 다음과 같이됩니다.

} finally {
    DbUtils.closeQuietly(rs);
    DbUtils.closeQuietly(ps);
    DbUtils.closeQuietly(conn);
}

그리고 실제로 Apache Commons DbUtils 에는 DbUtils정확하게이를 수행 하는 클래스가 있으므로 직접 작성할 필요가 없습니다.


3
감사합니다! conn! = null 문을 포착하거나 생각하지 않았습니다.
onaclov2000 2010

1
@ onaclov2000 예, rs, ps, conn할 수있다 null어디에 코드 바꿈에 따라. 이것이 이것이 "안전한"패턴으로 알려진 이유입니다.
Pascal Thivent

12
@Pascal Thivent : 사실 우리는 그들 모두를 닫을 필요가 없습니다. "Core Java Volume two-Advanced Features"책은 다음과 같이 썼습니다. 명령문에 열린 결과 세트가있는 경우 오브젝트 의 close메소드가 Statement연관된 것을 자동으로 닫습니다 ResultSet. 유사하게, close의 방법 Connection클래스는 모두 폐쇄 Statements의이 Connection.
Majid Azimi 2011

12
@Majid : 풀링 된 연결이 아니라면. 그러면 진술이 유출됩니다.
BalusC 2013 년

1
@BalusC : u는 풀링 된 연결의 Connection.close () 메소드를 사용하여 닫을 때 발생하는 설명해 주시겠습니까
Krsna Chaitanya

61

사용 후에는 항상 데이터베이스 / 리소스 개체를 닫는 것이 좋습니다. finally블록 에서 연결, 결과 집합 및 문 개체를 닫는 것이 좋습니다.

Java7까지 이러한 모든 리소스는 finally블록을 사용하여 닫아야합니다 . Java 7을 사용하는 경우 리소스를 닫기 위해 다음과 같이 할 수 있습니다.

try(Connection con = getConnection(url, username, password, "org.postgresql.Driver");
    Statement stmt = con.createStatement();
    ResultSet rs = stmt.executeQuery(sql);
) {

//statements
}catch(....){}

이제 con, stmt 및 rs 객체는 try 블록의 일부가되고 java는 사용 후 이러한 리소스를 자동으로 닫습니다.

도움이 되었기를 바랍니다.


내 진술이 묵시적이라면, 즉 블록 ResultSet rs = conn.createStatement().executeQuery(sql);내부에 try있습니까?
Antares42

1
종료를 위해 finally {} 블록에서 참조 할 수 없습니다. 예외가 발생하면 ResultSet의 close () 메소드가 호출되지 않습니다
Dan

닫지 않으면 어떻게됩니까?
Alex78191

닫지 않으면 메모리 누수가 발생할 수 있습니다.
Yadu Krishnan

14

그냥 닫습니다 충분 Statement하고 Connection. ResultSet개체 를 명시 적으로 닫을 필요가 없습니다 .

Java 문서는 다음에 대해 말합니다 java.sql.ResultSet.

ResultSet 개체는 해당 Statement 개체가 닫히거나 다시 실행될 때 생성 한 Statement 개체에 의해 자동으로 닫히거나 여러 결과 시퀀스에서 다음 결과를 검색하는 데 사용됩니다.


코멘트에 대해 BalusC에게 감사드립니다 : "나는 그것에 의존하지 않을 것입니다. 일부 JDBC 드라이버는 그것에 실패합니다."


25
나는 그것에 의존하지 않을 것입니다. 일부 JDBC 드라이버는 실패합니다. 예를 들어 "최대 열린 커서가 초과 됨"이있는 Oracle 등. 열려있는 모든 리소스를 명시 적으로 닫고 변명하지 마십시오.
BalusC 2013 년

1
나는보다는 어떤 사양을 준수 할 드라이버를 사용하지 것이다
Enerccio

2
BalusC가 지적했듯이 특정 공급자에 대한 종속성을 고정하는 대신 연결을 명시 적으로 닫는 것이 좋은 방어 프로그래밍입니다.
michaelok jul.

11

예. 결과 집합, 문 및 연결을 닫아야합니다. 연결이 풀에서 제공된 경우 연결을 닫으면 실제로 다시 풀로 다시 보내 재사용됩니다.

일반적으로 finally{}블록 에서이 작업을 수행 해야하므로 예외가 발생하더라도이를 닫을 기회가 있습니다.

많은 프레임 워크가이 리소스 할당 / 할당 해제 문제를 처리합니다. 예 : Spring의 JdbcTemplate . Apache DbUtils 에는 null 여부에 관계없이 결과 집합 / 문 / 연결을 닫은 후 (그리고 닫을 때 예외를 포착하는) 방법이 있습니다.


1
내가 "마지막"일식을 삽입하면 그것이 틀렸다는 것을 강조하는 것을 좋아합니다. 이것이 캐치 블록 뒤에 가야합니까?
onaclov2000 2010

예. try {} catch {} finally {}. catch {}는 선택 사항입니다. btw. 마지막처럼 {}
Brian Agnew

마지막으로 "close"문을 옮겼지만 "sqlexception"이라고 말하고 있습니다. 제안 사항이 있습니까?
onaclov2000 2010

1
close ()는 SQLException을 발생시킵니다. 당신은 그것을 처리해야합니다. 이를 자동으로 처리하려면 DbUtils.closeQuietly ()를 참조하십시오.
Brian Agnew

> conn.close ()가 발생하지 않으면 실제로 무슨 일이 일어나고 있습니까?
Alex78191

8

실제로 try-with-resources 블록을 사용하는 것이 가장 좋으며 try 블록을 종료하면 Java가 모든 연결을 자동으로 닫습니다.

AutoClosable을 구현하는 모든 개체로이 작업을 수행해야합니다.

try (Connection connection = getDatabaseConnection(); Statement statement = connection.createStatement()) {
    String sqlToExecute = "SELECT * FROM persons";
    try (ResultSet resultSet = statement.execute(sqlToExecute)) {
        if (resultSet.next()) {
            System.out.println(resultSet.getString("name");
        }
    }
} catch (SQLException e) {
    System.out.println("Failed to select persons.");
}

getDatabaseConnection에 대한 호출이 방금 구성되었습니다. JDBC SQL 연결 또는 풀에서 연결을 가져 오는 호출로 바꾸십시오.


이 경우 수동으로 연결을 닫을 필요가 없습니까?
Colin D

1
옳은. 연결을 명시 적으로 닫을 필요는 없습니다. try 코드 블록 끝에 도달하면 닫힙니다.
Joe

7

예, 연결을 종료해야합니다. 그렇지 않으면 데이터베이스 클라이언트는 일반적으로 소켓 연결 및 기타 리소스를 열어 둡니다.


... 종료 될 때까지. 이것은 클라이언트와 서버 측의 다양한 유한 자원을 묶습니다. 클라이언트가 이런 종류의 일을 너무 많이 수행하면 클라이언트 자체, 데이터베이스 서비스 및 클라이언트 또는 서버 시스템에서 실행되는 다른 응용 프로그램에 문제가 발생할 수 있습니다.
Stephen C
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.