자바 백엔드 입문 41편 — JDBC와 DataSource

2026-05-16자바 백엔드 입문

자바 백엔드 입문 41편. Phase 6 Data Access 시작. JDBC가 뭐고 DataSource가 왜 필요하고 커넥션 풀(HikariCP)이 어떻게 성능을 살리는지 수도꼭지 비유로 풀어쓴 학습 노트.

📚 자바 백엔드 입문 · 41편 — JDBC와 DataSource

이 글은 자바 백엔드 입문 시리즈 59편 중 41편이에요. Phase 5 Validation 2편이 끝났고, 이번 41편부터 Phase 6 Data Access 3편으로 들어갑니다. 자바 백엔드가 데이터베이스에 어떻게 연결하는지 — 가장 밑바닥인 JDBC와 DataSource 부터.

JDBC·DataSource가 헷갈리는 이유

처음 자바와 DB 연결을 배우면 JDBC·DriverManager·Connection·DataSource·커넥션 풀·HikariCP 같은 단어가 한꺼번에 쏟아져요. 무엇이 무엇을 감싸고 누가 누구를 호출하는지 안 잡혀요.

이 글에서는 수도꼭지 비유로 풀어요. DB = 저수지, JDBC 드라이버 = 정수장, Connection = 수도 파이프 한 개, DataSource = 집의 수도 시스템, 커넥션 풀 = "파이프 여러 개 미리 깔아두기". 끝까지 따라오시면 자바 백엔드가 DB에 연결되는 전체 그림이 한 번에 들어와요.

JDBC — 자바 표준 DB 연결 규격

JDBC(Java Database Connectivity) 는 자바가 "어떤 DB든 같은 방식으로 다루자" 라는 표준 API 규격이에요. 1997년 자바 1.1부터 들어 있어요.

핵심 발상 — 자바 코드는 "JDBC 인터페이스" 만 알면 되고, 실제 PostgreSQL·MySQL·Oracle 같은 DB와의 통신은 JDBC 드라이버가 처리해요.

[자바 코드]
    ↓ JDBC 인터페이스 (java.sql.*)
[JDBC 드라이버] ← DB마다 별도 jar (postgresql-jdbc.jar 등)
    ↓ DB 고유 프로토콜
[데이터베이스]

비유로 풀면 — JDBC = "국제 표준 콘센트", JDBC 드라이버 = "국가별 어댑터". 자바 코드는 "표준 콘센트에만 꽂으면 됨" 이고, 어댑터(드라이버)가 실제 국가별 콘센트(DB)에 맞춰 변환.

DB 종류별 드라이버

자주 만나는 드라이버들.

DB 드라이버 좌표
PostgreSQL org.postgresql:postgresql
MySQL com.mysql:mysql-connector-j
Oracle com.oracle.database.jdbc:ojdbc11
MariaDB org.mariadb.jdbc:mariadb-java-client
H2 (인메모리) com.h2database:h2
SQLite org.xerial:sqlite-jdbc

build.gradle 에 드라이버 의존성 박으면 — 자동으로 클래스 패스에 등록되어 "이 DB로 연결 가능" 상태가 돼요.

JDBC 원시 사용 코드 — 왜 직접 안 쓰나

JDBC를 직접 쓰는 코드는 정말 더러워요. 한 번 보자.

public Order findById(Long id) {
    Connection conn = null;
    PreparedStatement ps = null;
    ResultSet rs = null;
    try {
        conn = DriverManager.getConnection(url, user, password);
        ps = conn.prepareStatement("SELECT id, amount FROM orders WHERE id = ?");
        ps.setLong(1, id);
        rs = ps.executeQuery();
        if (rs.next()) {
            return new Order(rs.getLong("id"), rs.getInt("amount"));
        }
        return null;
    } catch (SQLException e) {
        throw new RuntimeException(e);
    } finally {
        if (rs != null) try { rs.close(); } catch (Exception ignore) {}
        if (ps != null) try { ps.close(); } catch (Exception ignore) {}
        if (conn != null) try { conn.close(); } catch (Exception ignore) {}
    }
}

한 SELECT 한 줄 짜는 데 20줄의 보일러플레이트 + try-catch-finally + 자원 정리. 비즈니스 로직은 "SELECT 한 줄" 뿐인데. 이게 1990년대 자바 코드의 실제 모습이었어요.

해결책 — JdbcTemplate(27편) 또는 JPA(29~32편) 같은 추상화 레이어. 28편에서 다룰 @Transactional 도 같이.

DataSource — 커넥션 관리 추상화

DriverManager.getConnection() 을 직접 호출하는 위 코드의 가장 큰 문제 — 매 요청마다 새 커넥션을 만든다. DB 커넥션은 "여는 데 100~500ms 걸리는 무거운 자원" 이라 — 매 요청 500ms를 커넥션 만드는 데 쓰면 백엔드가 굴러갈 수 없어요.

해결책이 DataSource. "이미 만들어둔 커넥션을 빌려주고, 끝나면 반납받는" 추상화. 커넥션 풀(Connection Pool) 이 핵심.

// DriverManager — 직접 커넥션 생성 (느림)
Connection conn = DriverManager.getConnection(url, user, password);

// DataSource — 풀에서 빌려옴 (빠름)
DataSource dataSource = ...;
Connection conn = dataSource.getConnection();   // 풀에서 즉시 반환
// ... 사용
conn.close();   // 실제 닫지 않고 풀에 반납

비유 — DriverManager = "매번 수도 공사를 새로 한다", DataSource 풀 = "수도 파이프 10개를 미리 깔아둔다". 누가 물 쓰겠다고 하면 즉시 한 파이프 빌려주고, 다 쓰면 반납.

HikariCP — Spring Boot의 기본 커넥션 풀

자바 진영의 커넥션 풀 라이브러리는 여러 개 — Apache DBCP·c3p0·Tomcat JDBC Pool·HikariCP. 현대 표준은 HikariCP.

  • 빠름 — 다른 풀 대비 2~10배 처리량
  • 가벼움 — 130KB 짜리 단일 jar
  • 검증된 안정성 — 대규모 운영 환경에서 사실상 표준

Spring Boot 2.0부터 HikariCP가 기본 커넥션 풀이에요. 별도 설정 없이 자동 사용.

Spring Boot의 application.yml 설정

Spring Boot에서 DB 연결 설정은 application.yml 한 파일에 다 박혀요.

spring:
  datasource:
    url: jdbc:postgresql://localhost:5432/myshop
    username: postgres
    password: secret
    driver-class-name: org.postgresql.Driver

    # HikariCP 설정 (모두 선택, 기본값 합리적)
    hikari:
      maximum-pool-size: 10           # 최대 커넥션 개수
      minimum-idle: 5                  # 최소 유휴 커넥션
      connection-timeout: 30000        # 커넥션 대기 타임아웃 (ms)
      idle-timeout: 600000             # 유휴 커넥션 정리 시간
      max-lifetime: 1800000            # 커넥션 최대 수명

JDBC URL 포맷:

DB URL 패턴
PostgreSQL jdbc:postgresql://host:5432/dbname
MySQL jdbc:mysql://host:3306/dbname
Oracle jdbc:oracle:thin:@host:1521:sid
H2 인메모리 jdbc:h2:mem:testdb

application.yml 박으면 Spring Boot가 자동으로 — DataSource Bean 생성 + HikariCP 풀 초기화 + JdbcTemplate Bean 등록. 우리는 그저 @Autowired private DataSource dataSource 로 받아 쓰면 끝.

DataSource Bean 직접 만들기 (Java Config)

application.yml 대신 Java Config로 박을 수도 있어요. 두 DB를 동시에 쓰는 시나리오 등.

@Configuration
public class DataSourceConfig {

    @Bean
    @ConfigurationProperties("spring.datasource.primary")
    public DataSource primaryDataSource() {
        return DataSourceBuilder.create().build();
    }

    @Bean
    @ConfigurationProperties("spring.datasource.secondary")
    public DataSource secondaryDataSource() {
        return DataSourceBuilder.create().build();
    }
}

대부분의 시스템은 DB 하나만 쓰니까 — application.yml 자동 설정으로 충분. Java Config는 "한 앱이 여러 DB 연결" 같은 특수 케이스에만.

커넥션 풀 크기 — 얼마가 적절한가

자주 받는 질문 — "maximum-pool-size 는 얼마로 박아야 하나?". 답은 CPU 코어 수 × 2 ~ 4 가 권장 시작점.

이유 — 한국 회사 백엔드는 보통 DB 작업이 "몇 ms 안에 끝나는 짧은 쿼리들" 이라, 커넥션 100개를 박아도 동시에 다 활성화되지 않아요. "DB가 동시에 처리 가능한 쿼리 수" 가 한계라 — 커넥션을 너무 많이 박으면 오히려 DB가 컨텍스트 스위칭으로 느려져요.

HikariCP 공식 가이드도 "커넥션 수보다 처리량 가속이 더 빠른 답" 이라고 명시. 10개로 시작해서 모니터링하면서 조정.

⚠️ 커넥션 누수 함정

JDBC를 직접 쓸 때 가장 위험한 함정 — 커넥션 누수. conn.close() 를 빠뜨리면 풀에 반납되지 않아 결국 모든 커넥션이 묶여 — DB가 응답 안 함. JdbcTemplate·JPA를 쓰면 자동 관리되니까 직접 JDBC 쓸 일은 거의 없어요.

DB·드라이버 호환성 점검

DB 버전과 드라이버 버전 호환성도 중요해요. 보통 한 번 박으면 변경 안 하니까 신경 안 써도 되지만.

  • PostgreSQL 16 + org.postgresql:postgresql:42.7.x 안전
  • MySQL 8.x + com.mysql:mysql-connector-j:8.x.x
  • Spring Boot가 자동으로 호환되는 드라이버 버전을 관리해줘서 — start.spring.io 에서 드라이버 추가만 하면 충돌 거의 없음

26편 한 줄 정리 — 다음 27편으로

한 줄 정리 — JDBC = 자바 표준 DB API. DataSource = 커넥션 관리 추상화. HikariCP = Spring Boot 기본 커넥션 풀. application.yml 한 번 박으면 Spring Boot가 자동으로 DataSource + 커넥션 풀 + JdbcTemplate 다 준비.

시험 직전 한 번 더 — JDBC·DataSource 입문자가 매번 헷갈리는 것

  • JDBC = Java Database Connectivity. 자바 표준 DB API (1997)
  • "국제 표준 콘센트" 같은 추상화. 자바 코드는 인터페이스만 알면 됨
  • JDBC 드라이버 = DB별 어댑터 (postgresql-jdbc·mysql-connector 등)
  • 드라이버 의존성 = build.gradle 에 박으면 자동 등록
  • DriverManager = JDBC 1.0의 커넥션 팩토리 (지금은 거의 안 씀)
  • 직접 JDBC = 20줄 보일러플레이트 + try-catch-finally
  • DataSource = 커넥션 관리 추상화 (DriverManager 후속)
  • 핵심 = 커넥션 풀(Connection Pool) — 미리 만들어둔 커넥션 빌려주기
  • DB 커넥션 생성 = 100~500ms (무거운 자원)
  • 풀에서 빌려오기 = 1ms 이내 (빠름)
  • 자바 진영 커넥션 풀 = HikariCP·DBCP·c3p0·Tomcat JDBC
  • HikariCP = Spring Boot 2.0+ 기본. 빠르고 가볍고 안정
  • Spring Boot = application.yml 박으면 자동 DataSource + HikariCP + JdbcTemplate
  • JDBC URL = jdbc:postgresql://host:5432/dbname 형식
  • maximum-pool-size = CPU 코어 × 2~4 권장 시작점
  • 너무 많은 커넥션 = DB가 컨텍스트 스위칭으로 느려짐
  • 커넥션 누수 = close() 빠뜨리면 풀 고갈
  • JdbcTemplate·JPA 쓰면 자동 관리 — 직접 JDBC 쓸 일 거의 없음
  • 두 개 이상 DB = Java Config로 DataSource Bean 명시
  • 한 DB만 = application.yml 자동 설정 충분

시리즈 다른 편 (앞뒤 글 모음)

이전 글:

다음 글:

※ 이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다.

답글 남기기

error: Content is protected !!