[Java] JDBC 정리

2025. 4. 1. 18:37·Java
728x90
반응형

JDBC 개요

JDBC 등장 배경

일반적으로 애플리케이션이 데이터베이스와 통신하려면 다음 과정을 거친다

  1. 커넥션 연결: TCP/IP를 사용하여 DB에 연결
  2. SQL 전달: 애플리케이션에서 SQL을 DB에 전송
  3. 결과 응답: DB가 SQL을 실행하고 결과를 반환

그러나, 데이터베이스마다 커넥션 방식, SQL 전달 방식, 응답 처리 방식이 달라 개발자는 매번 새로운 DB에 맞춰 코드를 변경해야 하는 문제가 있었다..

=> 이를 해결하기 위해 JDBC(Java Database Connectivity)가 등장

JDBC 표준 인터페이스

JDBC 표준 인터페이스 도입을 통한 의존성 역전

  • JDBC는 자바에서 데이터베이스에 접속할 수 있도록 설계된 표준 API
  • 애플리케이션과 데이터베이스 사이의 의존성 역전을 적용한 것
  • JDBC에서 제공하는 표준 인터페이스
    • java.sql.Connection: DB 연결 관리
    • java.sql.Statement: SQL 실행
    • java.sql.ResultSet: 쿼리 결과 처리
  • 개발자는 이 표준 인터페이스를 사용하여 데이터베이스 작업을 수행하면 됨
    • 각각의 데이터베이스마다 커넥션 연결, SQL 전달, 결과 응답 받는 방법을 새로 학습할 필요가 없음!
  • 하지만 JDBC 인터페이스 자체로는 동작하지 않으며, 각 DB 벤더에서 제공하는 JDBC 드라이버가 필요
    • 이는 각각의 DB 벤더(회사)에서 자신의 DB에 맞도록 구현해서 라이브러리로 제공 ex) mysql-connector-j

JDBC의 장점

  1. DB 변경 시 코드 수정 최소화: JDBC 표준 인터페이스를 사용하면 DB 벤더가 바뀌어도 JDBC 드라이버만 변경하면 되므로 애플리케이션 코드 변경이 최소화됩니다.
  2. 학습 부담 감소: 개발자는 JDBC 사용법만 익히면 다양한 DB에 적용할 수 있습니다.

참고: SQL 자체는 DB마다 일부 차이가 있으며, JPA를 사용하면 이런 차이를 더욱 줄일 수 있다.

JDBC와 최신 데이터 접근 기술

JDBC는 1997년에 등장한 오래된 기술이며, 사용이 번거로움..
=> 최근에는 JDBC를 직접 사용하기보다는 이를 편리하게 다룰 수 있는 기술이 등장함.

SQL Mapper

  • 장점: 반복적인 JDBC 코드를 줄여주고 SQL 응답을 객체로 변환해줌
  • 단점: SQL을 직접 작성해야 함
  • 대표 기술: JdbcTemplate, MyBatis

ORM (Object-Relational Mapping)

  • 특징: 객체와 DB 테이블을 자동으로 매핑하여 SQL 작성을 최소화
  • 장점: SQL을 직접 작성하지 않아도 되며, DB 변경 시 유연한 대응 가능
  • 단점: 학습 곡선이 가파름
  • 대표 기술: JPA (자바 진영 ORM 표준 인터페이스), Hibernate, EclipseLink (JPA 구현체)

주의: 내부적으로 모든 기술이 JDBC를 사용하므로 JDBC의 기본 개념은 반드시 알아야 함.


JDBC 사용

DB 연결 설정

@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(..)을 사용하여 DB 커넥션을 획득
  • 라이브러리에 등록된 JDBC 드라이버가 자동으로 감지되어 적절한 커넥션을 반환
  • JDBC DriverManager 연결 흐름
    1. DriverManager.getConnection() 호출
    2. DriverManager가 등록된 JDBC 드라이버를 탐색
    3. URL을 분석하여 적절한 드라이버를 선택
    4. 선택된 드라이버가 Connection 객체를 생성하여 반환

JDBC를 이용한 읽기와 쓰기

데이터 읽기 (Read)

public Member findById(String memberId) throws SQLException {
    String sql = "SELECT * FROM member WHERE member_id = ?";
    try (Connection con = getConnection();
         PreparedStatement pstmt = con.prepareStatement(sql)) {

        pstmt.setString(1, memberId);
        try (ResultSet rs = pstmt.executeQuery()) {
            if (rs.next()) {
                return new Member(rs.getString("member_id"), rs.getInt("money"));
            } else {
                throw new NoSuchElementException("Member not found: " + memberId);
            }
        }
    }
}
  • PreparedStatement를 사용하여 SQL 인젝션 방지
  • ResultSet을 사용하여 데이터 조회
  • rs.next()를 통해 데이터가 존재하는지 확인 후 객체 생성

ResultSet

  • 보통 select 쿼리의 결과가 순서대로 들어가 저장되는 자료구조
  • 내뷍 커서(cursor)를 이동시켜 다음 데이터 조회 가능
    • rs.next(): 커서를 다음으로 이동시킴. 최초의 커서는 데이터를 가리키고 있지 않기에 rs.next()를 최초 한번은 호출해야 데이터를 조회할 수 있음
    • rs.next()의 결과가 true면 데이터가 있는 것이고, false면 더 이상 데이터가 없다는 뜻
    • `rs.getString("member_id"): 현재 커서가 가리키고 있는 위치의 member_id 데이터를 String 타입으로 반환

데이터 쓰기 (Create, Update, Delete)

public Member save(Member member) throws SQLException {
    String sql = "INSERT INTO member(member_id, money) VALUES(?, ?)";
    try (Connection con = getConnection();
         PreparedStatement pstmt = con.prepareStatement(sql)) {

        pstmt.setString(1, member.getMemberId());
        pstmt.setInt(2, member.getMoney());
        pstmt.executeUpdate();
        return member;
    }
}
  • executeUpdate()로 데이터 삽입
  • try-with-resources 문법으로 자동 리소스 해제
  • 수정 및 삭제도 마찬가지임. sql만 바꿔주면 됨

DataSource 이해

커넥션을 얻는 방법은 앞서 학습한 JDBC DriverManager를 직접 사용하거나, 커넥션 풀을 사용하는 등 다양한 방법이 존재한

다. 애플리케이션에서 DriverManager를 사용해서 커넥션을 획득하다가 HikariCP 같은 커넥션 풀을 사용하도록 변경하면 커넥션을 획득하는 애플리케이션 코드도 함께 변경해야 한다..

=> 커넥션을 획득하는 방법을 추상화 하기 위한 추상화 인터페이스(DataSource)를 제공 (= 의존성 역전)

(JDBC 등장 배경과 유사)

 

DataSource 인터페이스

자바에서는 커넥션 획득 방식을 추상화하기 위해 javax.sql.DataSource 인터페이스를 제공한다.

public interface DataSource {
    Connection getConnection() throws SQLException;
}
  • 대부분의 커넥션 풀은 DataSource 인터페이스를 이미 구현하고 있으며, 이를 사용하면 커넥션 풀 기술을 쉽게 교체할 수 있다.
  • DriverManager는 DataSource 인터페이스를 사용하지 않으므로, 스프링에서는 DriverManagerDataSource 클래스를 제공하여 이를 해결한다.

DataSource - DriverManager 사용 예시

@Test
void dataSourceDriverManager() throws SQLException {
    DriverManagerDataSource dataSource = new DriverManagerDataSource(URL, USERNAME, PASSWORD);
    useDataSource(dataSource);
}

private void useDataSource(DataSource dataSource) throws SQLException {
    Connection con1 = dataSource.getConnection();
    Connection con2 = dataSource.getConnection();
    log.info("connection={}, class={}", con1, con1.getClass());
    log.info("connection={}, class={}", con2, con2.getClass());
}

DataSource - 커넥션 풀 (HikariCP) 사용 예시

@Test
void dataSourceConnectionPool() throws SQLException, InterruptedException {
    HikariDataSource dataSource = new HikariDataSource();
    dataSource.setJdbcUrl(URL);
    dataSource.setUsername(USERNAME);
    dataSource.setPassword(PASSWORD);
    dataSource.setMaximumPoolSize(10);
    dataSource.setPoolName("MyPool");

    useDataSource(dataSource);
    Thread.sleep(1000); // 커넥션 풀 초기화 대기
}
  • HikariCP를 사용하여 커넥션 풀을 구성하며, 커넥션 재사용을 통해 성능을 향상시킬 수 있다.

DataSource 적용 예제

MemberRepository

@Slf4j
public class MemberRepository {
    private final DataSource dataSource;

    public MemberRepository(DataSource dataSource) {
        this.dataSource = dataSource;
    }

    private Connection getConnection() throws SQLException {
        Connection con = dataSource.getConnection();
        log.info("get connection={}, class={}", con, con.getClass());
        return con;
    }
}
  • DataSource를 의존성 주입하여 DB 연결을 수행
  • 직접 DriverManager를 사용하는 것이 아니라 DataSource 인터페이스를 활용하여 커넥션을 획득

정리

  • JDBC는 자바의 표준 DB 연결 API이며, 기본 개념을 익혀야 한다.
  • DriverManager를 통해 JDBC 드라이버를 로드하고 DB에 연결한다.
  • PreparedStatement를 사용하여 SQL 인젝션을 방지한다.
  • JDBC는 직접 사용하기 복잡하므로, SQL Mapper(JdbcTemplate, MyBatis)나 ORM(JPA, Hibernate)와 함께 사용하는 것이 일반적이다.
  • DataSource를 사용하면 커넥션 풀을 활용하여 성능을 향상시킬 수 있다.
728x90
반응형

'Java' 카테고리의 다른 글

[Java] 소켓 통신과 네트워크 예외  (0) 2025.01.10
[Java] 제네릭(Generics)  (0) 2025.01.07
[Java] 스레드 풀 & ExecutorService  (0) 2025.01.07
[Java] 동시성 컬렉션  (0) 2025.01.06
[Java] CAS - 동기화와 원자적 연산  (1) 2025.01.06
'Java' 카테고리의 다른 글
  • [Java] 소켓 통신과 네트워크 예외
  • [Java] 제네릭(Generics)
  • [Java] 스레드 풀 & ExecutorService
  • [Java] 동시성 컬렉션
mxruhxn
mxruhxn
소소하게 개발 공부 기록하기
    반응형
    250x250
  • mxruhxn
    maruhxn
    mxruhxn
  • 전체
    오늘
    어제
    • 분류 전체보기 (152)
      • Java (21)
      • Spring (6)
      • Database (13)
      • Operating Syste.. (1)
      • Computer Archit.. (0)
      • Network (24)
      • Data Structure (6)
      • Algorithm (11)
      • Data Infra (7)
      • DevOps (12)
      • ETC (27)
      • Project (21)
      • Book (1)
      • Look Back (1)
  • 블로그 메뉴

    • 링크

      • Github
    • 공지사항

    • 인기 글

    • 태그

    • 최근 댓글

    • 최근 글

    • hELLO· Designed By정상우.v4.10.0
    mxruhxn
    [Java] JDBC 정리
    상단으로

    티스토리툴바