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) {
//
}