ch15_JDBC

통합 문서입니다.


1. JDBC

JDBC

학습 목표


1. JDBC란

JDBC(Java Database Connectivity)는 Java에서 RDBMS에 접근하는 표준 API다.

구성:

  1. 애플리케이션 코드
  2. JDBC API
  3. DB 벤더 드라이버
  4. 실제 데이터베이스

JDBC 아키텍처와 트랜잭션 흐름


2. 기본 실행 흐름

  1. DataSource 또는 DriverManagerConnection 획득
  2. SQL 준비 (PreparedStatement 권장)
  3. 파라미터 바인딩
  4. 실행 (executeQuery / executeUpdate)
  5. 결과 매핑 (ResultSet)
  6. 자원 해제

3. Connection과 자동 커밋

기본적으로 JDBC는 auto-commit이 켜져 있다.

conn.setAutoCommit(false);

여러 SQL을 하나의 원자 작업으로 묶으려면 직접 commit/rollback을 관리해야 한다.


4. PreparedStatement (필수)

String sql = "INSERT INTO users(name, age) VALUES(?, ?)";
try (PreparedStatement ps = conn.prepareStatement(sql)) {
    ps.setString(1, "Kim");
    ps.setInt(2, 20);
    ps.executeUpdate();
}

장점:

  1. SQL 인젝션 방지
  2. 파라미터 바인딩 명확
  3. SQL 파싱/실행 계획 재사용 가능성

5. ResultSet 매핑

String sql = "SELECT id, name, age FROM users";
try (PreparedStatement ps = conn.prepareStatement(sql);
     ResultSet rs = ps.executeQuery()) {
    while (rs.next()) {
        long id = rs.getLong("id");
        String name = rs.getString("name");
        int age = rs.getInt("age");
    }
}

매핑 시 컬럼명 오타/NULL 처리/타입 매핑 주의가 필요하다.


6. 트랜잭션 제어

conn.setAutoCommit(false);
try {
    // SQL 1
    // SQL 2
    conn.commit();
} catch (Exception e) {
    conn.rollback();
    throw e;
}

원칙:


7. 자원 관리

Connection, Statement, ResultSet는 반드시 닫아야 한다.

try (Connection conn = ds.getConnection();
     PreparedStatement ps = conn.prepareStatement(sql);
     ResultSet rs = ps.executeQuery()) {
    ...
}

try-with-resources가 표준 패턴이다.


8. DAO 계층 분리

권장 구조:

SQL 접근을 분리하면 테스트/유지보수성이 크게 향상된다.


9. 커넥션 풀(DataSource)

매 요청마다 물리 연결을 새로 만들면 비용이 크다.
실무에서는 HikariCP 같은 커넥션 풀을 사용한다.

효과:

  1. 연결 재사용
  2. 지연 감소
  3. 연결 수 제한/모니터링 가능

10. SQL 예외 처리 전략

  1. 기술 예외(SQLException)를 도메인 예외로 변환
  2. 쿼리/파라미터/트랜잭션 맥락 로그 기록
  3. 민감 정보는 로그에 직접 노출 금지

11. 보안/성능 체크포인트

  1. 문자열 연결 SQL 금지 (항상 바인딩)
  2. N+1 쿼리 패턴 점검
  3. 인덱스 전략 확인
  4. 대량 처리 시 배치(addBatch/executeBatch) 검토

12. 정리


2. 문제

문제

ch15 범위(Connection/PreparedStatement/ResultSet/Transaction/DAO) 문제입니다.


A. 연결/조회 기초

  1. JDBC Connection을 획득하고 연결 정보를 출력하시오.
  2. 단일 테이블 SELECT를 수행해 결과를 콘솔에 출력하시오.
  3. 조회 결과를 DTO 또는 record로 매핑하시오.

B. DML

  1. PreparedStatement로 INSERT를 구현하시오.
  2. UPDATE/DELETE를 각각 구현하시오.
  3. 영향받은 row 수를 검사해 성공/실패를 판단하시오.

C. 트랜잭션

  1. 계좌 이체 로직(출금+입금)을 하나의 트랜잭션으로 구현하시오.
  2. 중간 실패 시 롤백되는지 확인하시오.
  3. auto-commit on/off 차이를 실험하시오.

D. DAO 분리

  1. UserDao를 작성해 CRUD 메소드를 분리하시오.
  2. 서비스 계층에서 DAO를 사용해 유스케이스를 구성하시오.
  3. SQLException을 도메인 예외로 변환하시오.

E. 성능/안전

  1. 문자열 연결 SQL과 바인딩 SQL의 차이를 비교하시오.
  2. executeBatch로 대량 INSERT를 구현하시오.
  3. try-with-resources 누락 시 리소스 누수 문제를 재현하시오.

F. 챌린지

  1. 페이징 조회 API(LIMIT/OFFSET)를 구현하시오.
  2. 키워드 검색 조건을 동적으로 조합하되 SQL 인젝션 없이 구현하시오.
  3. 간단한 커넥션 풀 환경에서 동시 요청 테스트를 수행하시오.

제출 체크리스트

  1. 모든 SQL이 PreparedStatement 기반인가?
  2. 트랜잭션 경계가 명확한가?
  3. 자원 해제가 누락되지 않았는가?
  4. 예외 로그에 원인/맥락이 충분히 남는가?