Dev Language/Java

[자바/JDBC] 스프링-DB 1편 1. JDBC의 이해

ydin 2024. 1. 30. 13:20

JDBC 이해

애플리케이션을 개발할 때 중요한 데이터는 데이터베이스에 보관한다.

JDBC 등장 이유

데이터 처리를 위해 애플리케이션과 DB 간의 동작 방식은 다음과 같다.

  1. 커넥션 연결
  2. SQL(쿼리) 전달
  3. 결과 응답

여기서 발생할 수 있는 문제가 2가지 있다

  1. DB에 따른 코드 변경
    1. 데이터베이스를 변경할 경우(MySQL → Oracle), 각 db 마다 커넥션 연결, 쿼리 전달, 결과 응답 방법이 달라 관련 코드를 매번 수정해야 한다.
  2. 연결방식 학습
    1. 개발자가 데이터베이스에 맞는 커넥션 연결, 쿼리 전달, 결과 응답 방법을 새로 학습 해야한다.

→ 이 문제를 해결하기 위해 JDBC라는 자바 표준이 등장했다.

 

JDBC 표준 인터페이스

JDBC는 Java DataBase Connectivity의 약자로, 자바에서 DB에 접속할 수 있도록 하는 자바 API다.

JDBC는 DB에서 자료를 쿼리하거나 업데이트하는 방법을 제공한다.

 

  • JDBC가 제공하는 기능
    • java.sql.Connection : 연결
    • java.sql.Statement : SQL을 담은 내용
    • java.sql.ResultSet : SQL 요청 응답

인터페이스만으로는 기능이 동작하지 않기에 인터페이스를 구현한 JDBC 드라이버(DB 벤더(회사)에서 자신의 DB에 맞도록 구현한 라이브러리)를 사용해야 DB 기능을 사용할 수 있다.

 

  • 문제 해결
    • DB 독립적
      • 이제 애플리케이션 로직은 JDBC 표준 인터페이스에만 의존하기 때문에 DB를 변경하고 싶으면 JDBC 구현 라이브러리만 변경하면 된다. 따라서 코드를 변경하지 않아도 된다.
    • 간편하고 표준화된 사용법
      • 개발자는 이제 JDBC 표준 인터페이스 사용법만 학습하면 된다. 학습에 필요한 시간이 단축되었다
  • 주의
    • 인터페이스로 어느정도 표준화를 했지만, 페이징 SQL은 각 DB마다 사용법이 달라 이 부분은 맞춤으로 설정해야 한다

 

JDBC와 최신 데이터 접근 기술

JDBC는 출시된지 오래되었고(1997년), 사용법도 복잡하다. 그래서 SQL Mapper, ORM 기술 같이 JDBC를 편리하게 사용하는 다양한 기술이 존재한다.

 

  • SQL Mapper

  • 대표 기술 : 스프링 JdbcTemplate, MyBatis
  • 장점 - JDBC를 편리하게 사용하도록 도와줌
    • SQL 응답 결과를 객체로 편리하게 변환해줌
    • JDBC의 반복 코드를 제거해줌
    • SQL만 작성할 줄 알면 금방 사용 가능
  • 단점
    • 개발자가 SQL을 직접 작성해야 함

 

  • ORM

  • 대표 기술 : JPA, 하이버네이트(레퍼런스 많고, 디테일한 기능 많이 제공), 이클립스링크
  • 객체를 관계형 데이터베이스 테이블과 매핑해주는 기술
  • 장점
    • ORM이 SQL을 동적으로 생성하기에 반복적인 SQL 직접 작성하지 않아도 됨
    • 개발 생산성 향상
  • 단점
    • 기술이 복잡해 깊이있게 공부한 후 사용해야 함

 

중요

SQL Mapper, JPA 기술이 JDBC 사용을 편리하게 해주지만, 결국 기반은 모두 JDBC를 사용한다. 따라서 JDBC를 직접 사용하지 않아도 JDBC가 어떻게 동작하는지 기본 원리를 알아두어야 한다. JDBC는 자바 개발자라면 꼭 알아두어야 하는 필수 기본 기술이다.

 

DriverManager

JDBC가 제공하는 DriverManager는 다음과 같은 기능을 제공한다.

  • 라이브러리에 등록된 DB 드라이버들 관리
  • 커넥션 획득

  1. 애플리케이션 로직에서 커넥션이 필요할 시 DriverManager.getConnection() 호출
  2. DriverManager가 라이브러리에 등록된 드라이버 목록을 자동으로 인식
  3. 정보를 넘겨 커넥션이 획득 가능한지 확인
    1. URL(jdbc:[db 이름]:~), USERNAME, PASSWORD
  4. 이렇게 찾은 커넥션 구현체가 클라이언트에 반환

 

JDBC 개발 - 생성

JDBC를 이용해 DB 작업을 하려면 DriverManager로 DB와 연결 후 SQL을 보낸 뒤 결과를 받고 종료하는 순서로 로직을 작성하면 된다.

 

Member 테이블에 회원을 등록하는 예시인데, 구체적인 코드는 다음과 같다.

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) {
	// 실행한 역순서(ResultSet -> PreparedStatement -> Connection)로 객체 종료
	// ResultSest null 체크 후 종료
	// Statement null 체크 후 종료
	// Connection null 체크 후 종료	
}

private Connection getConnection() {
	return DBConnectionUtil.getConnection();
}

 

 

JDBC 개발 - 조회

이전에 저장한 데이터를 조회해보자. 대부분의 로직이 생성 로직과 비슷하지만, 결과를 반환하는 ResultSet과 Cursor 내용이 다르다.

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();

          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);
	} 
}

 

  • rs.next()
    • ResultSet 내부에 있는 커서를 이동해 다음 데이터를 조회할 수 있다
    • 위 함수를 이용하면 커서가 다음으로 이동한다.
    • 최초의 커서는 데이터를 가리키고 있지 않기 때문에 rs.next()를 최초 한번은 호출해야 데이터 조회가 가능하다
    • rs.next() == true : 커서 이동 결과 데이터가 존재한다
    • rs.next() == false : 커서 이동 결과 데이터가 존재하지 않는다(더 조회할 데이터가 없다)

 

 

Reference

인프런 김영한 - '스프링 DB 1편 - 데이터 접근 핵심 원리'