Spring에서의 JDBC

hoyong.eom·2023년 8월 3일
0

스프링

목록 보기
27/59
post-thumbnail

Spring

JDBC의 이해

초창기의 애플리케이션과 데이터베이스를 연결해서 사용하기 위해서는 데이터베이스마다 커넥션 연결, SQL을 전달하는 방법, 그리고 그 결과를 응답받는 방법이 모두 달랐다고 한다.

따라서 여기에는 큰 문제 2가지가 있었다.

  • 데이터베이스를 다른 종류의 데이터베이스로 변경하면 애플리케이션 서버에 개발된 데이터베이스 사용 코드도 함께 변경해야한다.
  • 개발자가 각각의 데이터베이스마다 커넥션 연결, SQL 전달, 그리고 그 결과를 응답 받는 방법을 새로 학습해야 한다.

이러한 문제들을 해결하기 위해서 JDBC 라는 자바 표준이 등장한것이라고 한다.(데이터베이스 마다 사용 방법이 모두 다르니까 이러한 표준을 만들어서 등장한게 JDBC !!)

JDBC 표준 인터페이스

JDBC(Java Database Connectivity)는 자바에서 데이터베이스에 접속할 수 있도록 하는 자바 API다.

대표적으로 다음 3가지 기능을 표준 인터페이스로 정의해서 제공한다.

  • java.sql.Connection : 데이터 베이스 연결
  • java.sql.Statement : SQL을 담은 내용
  • java.sql.ResultSet : SQL 요청 응답

따라서 자바는 표준 인터페이스를 정의해두었기 때문에 개발자는 이 표준 인터페이스만 사용해서 개발하면 된다.
이 JDBC 인터페이스를 각각 DB 벤더에서 자신의 DB에 맞도록 구현해서 라이브러리로 제공하는데 이것을 JDBC 드라이버라고 한다.

따라서, JDBC의 등장으로 다음 2가지 문제가 해결되었다.

  • 데이터베이스를 다른 종류의 데이터베이스로 변경하면 애플리케이션 서버의 데이터베이스 사용 코드도 함께 변경해야하는 문제
    - 애플리케이션 로직은 JDBC 표준 인터페이스에만 의존한다. 따라서데이터베이스를 다른 종류의 데이터베이스로 변경하고 싶으면 JDBC구현 라이브러리만 변경하면 된다. 따라서 다른 종류의 데이터베이스로 변경해도 애플리케이션 서버의 사용 코드를 그대로 유지할 수 있다.
  • 개발자가 각각의 데이터베이스 마다 커넥션 연결, SQL 전달, 그리고 결과를 응답받는 방법을 새로 학습할 필요가 없다. JDBC 표준 인터페이스 사용법만 익히면 된다.

JDBC 기본 예시 코드

아래의 코드는 데이터베이스에 연결하기 위한 데이터베이스 커넥션을 얻어오는 예시 코드이다.

@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)를 사용하면
라이브러리에 있는 데이터베이스 드라이버를 찾아서 해당 드라이버가 제공하는 커넥션을 반환해준다.

  • JDBC는 java.sql.Connection 표준 커넥션 인터페이스를 정의한다.
  • H2 데이터베이스 드라이버는 JDBC Connection 인터페이스를 구현한 org.h2.jdbc.JdbcConnection 구현체를 제공한다.

DriverManager가 커넥션을 효청하는 상세한 Flow는 아래와 같다.

JDBC가 제공하는 DriverManager는 라이브러리에 등록된 DB 드라이버들을 관리하고 커넥션을 획득하는 기능을 제공한다.

  1. 애플리케이션 로직에서 커넥션이 필요하면 DriverManager().getConnect()을 호출한다.
  2. DriverManager는 라이브러리에 등록된 드라이버 목록을 자동으로 인식한다. 이 드라이버들에게 순서대로 다음의 정보를 넘겨서 커넥션을 획득할 수 있는지 확인한다.

JDBC 조회 예시 코드

 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편-데이터 접근 핵심 원리

0개의 댓글