JDBC (Java DataBase Connectivity)

zwon·2023년 9월 5일
0

Java

목록 보기
2/4

애플리케이션을 개발할 때 다음과 같이 데이터베이스와 연결한다.

그런데, 과거에는 DB마다 커넥션 연결, SQL 전송 방법 등이 다 달라서 만약 DB를 변경하면 관련 코드들을 싹 바꿔야하는 번거로움이 있었다.

그래서 JDBC라는 자바 표준이 나왔다.


JDBC (Java DataBase Connectivity)

  • 자바 표준 API로 자바에서 DB에 접속할 수 있도록 한다.
  • JDBC는 위와 같은 커넥션 연결, SQL전송, 결과 응답을 다음과 같은 표준으로 정의 했다.

  • 이러한 JDBC 표준들이 각 DB에 맞도록 구현되어있어야 각 DB들을 사용할 수 있다.
  • 그래서 JDBC는 각 DB에 맞도록 JDBC를 구현해서 라이브러리로 제공해준다.
  • 이를 JDBC 드라이버라고한다.
    • MySQL DB에 접근할 수 있는 JDBC 드라이버는 MySQL JDBC 드라이버고한다.

  • 그래서 개발자들은 JDBC 표준만 사용해서 개발을 하면 된다.

JDBC 접근 기술

JDBC는 과거 기술이고 JDBC를 직접 사용하기에는 복잡하기 때문에 이러한 JDBC를 편리하게 사용할 수 있는 기술들이 등장했다

SQL Mapper

  • JDBC를 편하게 사용할 수 있지만 개발자가 직접 SQL을 작성해야한다.
  • SQL Mapper 대표 기술로는 JdbcTemplate과 MyBatis가 있다.

ORM (Object Relation Mapping)

먼저 ORM이란 Object 객체를 관계형 DB 테이블과 매핑해주는 기술이다.

  • ORM역시 JDBC를 편하게 사용할 수 있다. SQL을 작성하지 않아도 된다. 하지만어려운 기술이어서 기술에 대한 이해가 탄탄해야한다.
    ORM 대표 기술로는 JPA가 있고 JPA의 구현체로는 하이버네이트가 있다.

위에서 되게 자주 보이는 단어가 있다.
JDBC다. 즉 근본 기술인 JDBC의 동작 원리를 알고이었어야 한다.
이제 코드로 JDBC에 대해 알아보자.


우선 여기선 학습용으로 좋은 H2 데이터베이스를 사용한다.
우선 H2 데이터베이스에 접속하기 위한 기본 정보들인 URL과 USERNAME, PASSWORD들은 자주 사용할테니 상수로 정의한다.

DB 연결

public abstract class ConnectionConst {
  public static final String URL = "jdbc:h2:tcp://localhost/~/test";
  public static final String USERNAME = "sa";
  public static final String PASSWORD = "";
}

Connection 얻기

  • java.sq의 Connection을 사용해야한다.
public class DBConnectionUtil {

  public static Connection getConnection() {
    try {
      Connection connection = DriverManager.getConnection(URL, USERNAME, PASSWORD);
      return connection;
    } catch (SQLException e) {
      throw new IllegalStateException(e);
    }
  }
}
  • DB에 연할려면 JDBC가 제공하는 DriverManager.getConnection(...)을 사용해야한다.
  • DriverManager.getConnection(...)을 사용하면 DB 드라이버를 찾아서 해당 드라이버가 제공하는 Connection을 반환해준다.
  • 즉 위 코드에서는 H2 DB 드라이버가 작동하고 이 드라이버가 Connection을 반환함.

H2 DB 드라이버를 어떻게 찾았을까?

DriverManager는 라이브러리에 등록된 DB 드라이버들의 목록을 자동으로 인식하고, 이러한 드라이버들을 관리하고 커넥션을 획득하는 기능을 제공해준다.

어떻게 찾았는지는 다음과 같은 프로세스를 거친다.

  1. 커넥션 획득을 위해 DriverManager.getConnection(...) 호출

  2. 라이브러리에 등록된 드라이버들에게 파라미터로 넘겨온 정보들을 넘긴다.

    • URL, USERNAME, PASSWORD : DB 접속에 필요한 정보
  3. 각각의 드라이버들이 URL을 보고 자신이 처리할 수 있는 데이터베이스인지 아닌지를 확인한다.

    • jdbc:h2~은 h2 DB에 접근하기 위한 규칙임.
    • 그래서 자신이 처리할 수 없다면 다음 드라이버가 처리 시도를 한다.
  4. 3번 과정을 거치면서 처리할 수 있는 드라이버를 찾으면 해당 드라이버가 실제 DB와 연결해서 Connection을 획득하고 반환한다.

Statement로 SQL 전송하기

다음과 같이 Member 테이블이 있다고 하자.

Member 테이블에 데이터를 추가하는 코드를 보자.

  public Member save(Member member) throws SQLException{
    String sql = "insert into member(member_id, money) values(?,?)";
    Connection con = null;
    // Preparestatement를 가지고 DB에 쿼리를 날리는 것
    PreparedStatement pstmt = null;

    try {
      // Connection 가져오는 부분
      con = DBConnectionUtil.getConnection();
      // DB에 날릴 SQL을 등록
      pstmt = con.prepareStatement(sql);
      // (?, ?) 파라미터 바인딩
      pstmt.setString(1, member.getMemberId()); // 1번 파라미터 - member_id
      pstmt.setInt(2, member.getMoney()); // 2번 파라미터 - money
      pstmt.executeUpdate(); // 쿼리를 실제 DB에 날리는 것 = 실행
      return member;
    }catch(SQLException e) {
      log.info("db error", e);
      throw e;
    }finally {
      // 시작과 역순으로 close 해주기
      // 근데 pstmt에서 Exception이 발생하면 con.close()가 실행되지 않을 수 있어서 다음과 같은 처리를 해주어야함.
      close(con, pstmt, null);
    }
  }
  • String sql에 DB에 날릴 쿼리문을 정의했다.
  • con.prepareStatement(sql)을 통해서 DB에 날릴 쿼리문과 ?, ? 즉 파라미터를 바인딩할 준비가 되었다.
  • 파라미터 바인딩
    • pstmt.setString(1, member.getMemberId());
    • pstmt.setInt(2, member.getMoney());
    • 앞의 숫자는 파라미터 위치, 2번째는 파라미터 값
  • pstmt.executeUpdate();을 통해 쿼리문을 실제 DB에 전달함.
    • 참고로 반환값이 있는데 반환값은 영향받은 DB row 수를 반환해줌.
  • DB에 대한 작업이 끝났으면 사용했던 리소스들을 닫아줘야하는데 닫아줄때는 역순으로 닫아주면 된다.
    그래서 원래는 pstmt.close()를 한 다음에 con.close()를 해줘야하는데 만약 pstmt.close()를 실행하다가 예외가 발생할 경우 con.close()가 실행되지 않을 수 있다.
    그래서 각각 pstmt.close()와 con.close()를 예외처리를 해줘야하는데 코드가 길어져서 close()라는 메서드를 만들었다.
    여기서는 우선 ResultSet도 닫아줬는데 우선 여기서는 사용하지 않아 null로 값을 넘겼다.

private void close(Connection con, Statement stmt, ResultSet rs){
    // Statement는 쿼리를 바로 넣는 것이고
    // preparestatement는 파라미터를 바인딩할 수 있는 것
    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 (stmt != null) {
      try {
        con.close();
      } catch (SQLException e) {
        log.info("error",e);
      }
    }

  }
  • 예외 처리를 해주면서 리소스를 close()를 해주는 코드이다.
  • 순서는 역순이라는 점을 주의하자.

ResultSet

id를 가지고 Member를 조회하는 코드이다.
save()와는 쿼리문은 다르겠지만 되게 비슷한 부분의 설명은 넘어가겠다.
그리고 조회하는 쿼리문의 실행은 pstmt.executeQuery()이며 반환값으로는 조회 결과를 ResultSet 타입으로 받는다.

public Member findById(String memberId) throws SQLException{
    String sql = "select * from member where member_id = ?";
    Connection con = null;
    PreparedStatement pstmt = null;
    ResultSet rs = null;

    try {
      con = getConnection();
      pstmt = con.prepareStatement(sql);
      pstmt.setString(1, memberId);

      rs = pstmt.executeQuery(); // 조회하는 쿼리를 날릴때 사용하는 메서드이며 반환값은 ResultSet
      if (rs.next()){
        Member member = new Member();
        member.setMemberId(rs.getString("member_id"));
        member.setMoney(rs.getInt("money"));
        return member;
      }else{
        throw new NoSuchElementException("member not found memberId="+memberId);
      }

    } catch (SQLException e){
      log.error("db error", e);
      throw e;
    } finally {
      close(con, pstmt, rs);
    }
  }
  • ResultSet은 내부에 Cursor를 가지고 있어 처음엔 한번은 rs.next()를 실행해주어야 실제 데이터가 있는 부분부터 시작할 수 있다. 왜냐하면 처음엔 커서가 아무곳도 가르키고있지 않아서 한번은 호출해줘야한다.
    • rs.next()가 true면 커서 이동 결과가 데이터가 있다는 뜻.
    • s.next()가 false면 데이터가 없다는 뜻.
    • 그래서 else문은 데이터가 없다는 예외를 발생시켜주었다.
  • 그 다음, 멤버 객체를 생성한 후 ResultSet으로 가져온 값들을 setXxx()해준 다음에 반환해주면 된다.
    • 가져올 값들의 타입에 맞게 rs.getString(...), rs.getInt(...)를 사용하여 가져왔다.

속성이 2개밖에 없는 테이블에 데이터를 insert와 select하는 간단한 쿼리문만 작성했는데 코드의 양은 어마무시하다. 수정, 삭제도 비슷하게 구현이 될텐데 코드 양이 어마무시할 것이다.

그래서 ORM이나 SQL Mapper기술이 나왓다 싶다...............


본 포스팅은 스프링 DB 1편를 공부하면서 정리한 글입니다.

profile
Backend 관련 지식을 정리하는 Back과사전

0개의 댓글

관련 채용 정보