Java

[JDBC] Try-with-resources

JDBC API를 직접 사용하는 경우, Connection, PreparedStatement, ResultSet을 어떻게 하면 잘 닫을 수 있을까?

이 때, 사용할 수 있는 방법이 Try-with-resources이다.

Try-with-resources

try문 내부에 우리가 사용할 객체를 명시해준다. 이렇게 하면, try-catch 구문을 벗어날 때 해당 객체의 close() 메서드를 호출한다. 따라서 따로 close();를 일일히 해주지 않아도 된다 :)


public void delete(String name) throws SQLException {
    String query = "DELETE FROM History WHERE Name = ?";
    try (Connection connection = DriveManager.getConnection();
         PreparedStatement preparedStatement = connection.prepareStatement(query)) {
        preparedStatement.setString(1, name);
        preparedStatement.executeUpdate();
    } catch (SQLException e) {
        System.err.println(e.getMessage());
    }
}

그렇다면, preparedStatement.setString(1, name); 과 같이 쿼리에 변수가 포함되는 데다가 ResultSet이 필요한 경우엔 어떻게 해야할까?
우선 첫번째 try 내부에서 Connection과 PreparedStatement를 선언한다. 그 후 내부에서 setString을 해 쿼리를 완성한 다음에서야 다시 try문에서 ResultSet을 선언할 수 있다. 이렇게 되면 단점은 indent-depth가 2로 늘어나게 된다 :(

public Optional<Integer> findIdByName(String name) throws SQLException {
    String query = "SELECT * FROM TABLE_NAME WHERE Name = ?";
    Optional<Integer> id = Optional.empty();
    try (Connection connection = DriveManager.getConnection();
         PreparedStatement preparedStatement = connection.prepareStatement(query)) {
        preparedStatement.setString(1, name);
        try (ResultSet rs = preparedStatement.executeQuery()) {
            if (!rs.next()) return id;
            id = Optional.of(rs.getInt("id"));
        }
    } catch (SQLException e) {
        System.err.println(e.getMessage());
    }
    ...
}

만약 자바 9이상이라면, try문이 아니더라도 위에서 먼저 Connection, PreparedStatement, ResultSet 등을 선언한 뒤 try에서는 다음과 같이 간단하게 변수명만 명시해 사용할 수 있다.

Connection connection = getConnection();
PreparedStatement pstmt = connection.preparedStatement(query);
ResultSet rs = pstmt.executeQuery();
try (connection, pstmt, rs) {
    //
} catch (SQLException e) {
    //
}