초창기의 애플리케이션과 데이터베이스를 연결해서 사용하기 위해서는 데이터베이스마다 커넥션 연결, SQL을 전달하는 방법, 그리고 그 결과를 응답받는 방법이 모두 달랐다고 한다.
따라서 여기에는 큰 문제 2가지가 있었다.
이러한 문제들을 해결하기 위해서 JDBC 라는 자바 표준이 등장한것이라고 한다.(데이터베이스 마다 사용 방법이 모두 다르니까 이러한 표준을 만들어서 등장한게 JDBC !!)
JDBC(Java Database Connectivity)는 자바에서 데이터베이스에 접속할 수 있도록 하는 자바 API다.
대표적으로 다음 3가지 기능을 표준 인터페이스로 정의해서 제공한다.
따라서 자바는 표준 인터페이스를 정의해두었기 때문에 개발자는 이 표준 인터페이스만 사용해서 개발하면 된다.
이 JDBC 인터페이스를 각각 DB 벤더에서 자신의 DB에 맞도록 구현해서 라이브러리로 제공하는데 이것을 JDBC 드라이버라고 한다.
따라서, JDBC의 등장으로 다음 2가지 문제가 해결되었다.
아래의 코드는 데이터베이스에 연결하기 위한 데이터베이스 커넥션을 얻어오는 예시 코드이다.
@Slf4j
public class DBConnectionUtil {
public static Connection getConnection() {
try {
Connection connection = DriverManager.getConnection(URL, USERNAME,
PASSWORD);
log.info("get connection={}, class={}", connection,
connection.getClass());
return connection;
} catch (SQLException e) {
throw new IllegalStateException(e);
}
}
}
DriverManager.getConnection(URL, USERNAME, PASSWORD)를 사용하면
라이브러리에 있는 데이터베이스 드라이버를 찾아서 해당 드라이버가 제공하는 커넥션을 반환해준다.
DriverManager가 커넥션을 효청하는 상세한 Flow는 아래와 같다.
JDBC가 제공하는 DriverManager는 라이브러리에 등록된 DB 드라이버들을 관리하고 커넥션을 획득하는 기능을 제공한다.
public Member save(Member member) throws SQLException {
String sql = "insert into member(member_id, money) values(?, ?)";
Connection con = null;
PreparedStatement pstmt = null;
try {
con = getConnection();
pstmt = con.prepareStatement(sql);
pstmt.setString(1, member.getMemberId());
pstmt.setInt(2, member.getMoney());
pstmt.executeUpdate();
return member;
} catch (SQLException e) {
log.error("db error", e);
throw e;
} finally {
close(con, pstmt, null);
}
}
private void close(Connection con, Statement stmt, ResultSet rs) {
if (rs != null) {
try {
rs.close();
} catch (SQLException e) {
log.info("error", e);
}
}
if (stmt != null) {
try {
stmt.close();
} catch (SQLException e) {
log.info("error", e);
}
}
if (con != null) {
try {
con.close();
} catch (SQLException e) {
log.info("error", e);
}
}
}
private Connection getConnection() {
return DBConnectionUtil.getConnection();
}
위 코드는 간단히 데이터베이스에서 JDBC를 이용해서 Member를 조회하는 코드이다.
사실 JDBC를 직접 사용할 일은 거의 없기 때문에 위 코드가 중요하진 않다.
다만, 위 코드에서 리소스를 정리하는 부분은 매우 중요하다.
쿼리를 실행하고 나면 리소스를 정리해야한다. 위 코드에서는 Connection, PreparedStatement를 사용한다. 리소스를 정리할때는 항상 역순으로 해야한다.
Connection을 먼저 획득하고 Connection을 통해 PreparedStatement를 만들었기 떄문에 리소스를 반환할때는 PreparedStatement를 먼저 종료하고 그다음에 Connection을 종료해야한다.
리소스 정리는 반드시 수행되어야 하므로 예외가 발생하든 하지 않든 항상 수행되어야 하므로 finally 구문에 주의해서 작성해야한다.
참고
PreparedStatement는 Statement의 자식 타입인데, "?"를 통한 파라미터 바인딩을 가능하게 해준다. 참고로 SQL Injection 공격을 예방하려면 PreparedStatement를 통한 파라미터 바인딩 방식을 사용해야한다.
해당 포스팅은 아래의 강의를 공부하여 정리한 내용입니다
김영한님의 SpringDB1편-데이터 접근 핵심 원리