커넥션풀과 DataSource
- 김영한님의 스프링 DB 1편 강의를 통해 커넥션 풀의 개념과 동작 원리를 이해하고,
DataSource인터페이스를 활용하여 커넥션 획득 방법을 추상화하는 방법을 정리함
커넥션 풀 이해
데이터베이스 커넥션 획득 과정

- DB 드라이버를 통해 커넥션 조회
- DB와 TCP/IP 커넥션 연결 (3-way handshake)
- ID, PW와 기타 부가정보를 DB에 전달
- DB가 내부 인증 완료 후 DB 세션 생성
- DB가 커넥션 생성 완료 응답 전송
- DB 드라이버가 커넥션 객체를 생성해서 반환
커넥션 매번 생성의 문제점
- 과정이 복잡하고 시간이 많이 소모됨
- DB와 애플리케이션 서버 모두 리소스 사용
- 응답 속도에 영향
- SQL 실행 시간 + 커넥션 생성 시간
- 사용자 경험 저하
커넥션 풀 개념
커넥션 풀 (Connection Pool)
- 커넥션을 미리 생성해두고 사용하는 방법
- 커넥션을 미리 생성하여 풀에 보관
- 필요 시 가져다 사용
- 사용 후 풀에 반환 (종료 X)
커넥션 풀 동작 방식

- 초기화
- 애플리케이션 시작 시점에 필요한 만큼 커넥션 미리 확보 (기본 10개)
- TCP/IP로 DB와 연결된 상태 유지
- 사용
- 커넥션 풀에서 이미 생성된 커넥션을 참조로 가져옴
- 빠른 속도로 SQL 전달 가능
- 반환
- 커넥션을 종료하지 않고 살아있는 상태로 반환
- 다음에 다시 사용 가능
- 커넥션 반환 시
close()를 호출하지만 실제 종료가 아닌 풀에 반환됨
커넥션 풀의 장점
- 빠른 응답 속도
- 커넥션 생성 시간 제거
- 리소스 절약
- 매번 TCP/IP 연결 불필요
- DB 보호
- 최대 커넥션 수 제한 가능
- 무한정 연결 방지
커넥션 풀 오픈소스
| 오픈소스 | 특징 |
|---|---|
| commons-dbcp2 | 아파치 커먼즈 |
| tomcat-jdbc pool | 톰캣 JDBC |
| HikariCP | 고성능, 스프링 부트 기본 |
DataSource 이해
커넥션 획득 방법의 변화
- 애플리케이션에서 커넥션을 획득하는 방법은 다양함
- JDBC
DriverManager직접 사용 - 커넥션 풀 사용 (
HikariCP등)
- JDBC
DriverManager 사용의 문제점
DriverManager를 사용하다가HikariCP같은 커넥션 풀로 변경하려면?- 애플리케이션 코드 변경 필요
- 의존 관계 변경 필요
- 사용법이 서로 다름
DataSource 추상화
javax.sql.DataSource 인터페이스
- 커넥션을 획득하는 방법을 추상화한 인터페이스

핵심 기능
1
2
3
public interface DataSource {
Connection getConnection() throws SQLException;
}
- 커넥션을 조회하는 하나의 메서드만 제공
- 구현체만 변경하면 애플리케이션 코드는 수정 불필요
- 애플리케이션은
DataSource인터페이스에만 의존
DataSource 구현체
- 커넥션 풀
- 대부분의 커넥션 풀이
DataSource인터페이스를 구현 HikariCP,DBCP2등
- 대부분의 커넥션 풀이
- DriverManager
DataSource인터페이스를 사용하지 않음- 스프링이 제공하는
DriverManagerDataSource사용DriverManager를DataSource로 사용 가능하도록 어댑터 역할
DataSource 예제1 - DriverManager
DriverManager 직접 사용
1
2
3
4
5
@Test
void driverManager() throws SQLException {
Connection con1 = DriverManager.getConnection(URL, USERNAME, PASSWORD);
Connection con2 = DriverManager.getConnection(URL, USERNAME, PASSWORD);
}
- 커넥션을 획득할 때마다 URL, USERNAME, PASSWORD를 계속 전달해야 함
DriverManagerDataSource 사용
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/**
* 스프링이 제공하는 DriverManagerDataSource 사용
*/
@Test
void dataSourceDriverManager() throws SQLException {
// DataSource 생성 시 한 번만 파라미터 설정
DriverManagerDataSource dataSource = new DriverManagerDataSource(URL, USERNAME, PASSWORD);
useDataSource(dataSource);
}
private void useDataSource(DataSource dataSource) throws SQLException {
// 이후에는 getConnection()만 호출
Connection con1 = dataSource.getConnection();
Connection con2 = dataSource.getConnection();
}
DataSource객체 생성 시 한 번만 접속 정보 설정- 이후에는
getConnection()만 호출하면 됨
설정과 사용의 분리
-
DataSource를 사용하면 설정과 사용을 분리할 수 있음 - 설정
DataSource객체를 생성하면서 필요한 속성 입력- URL, USERNAME, PASSWORD를 한 곳에서 관리
- 사용
getConnection()만 호출- 접속 정보를 몰라도 됨
- 장점
- Repository는
DataSource만 의존하면 됨 - 접속 정보가 변경되어도 사용하는 코드는 변경 불필요
- 설정 부분과 사용 부분이 명확히 분리됨
- Repository는
DataSource 예제2 - 커넥션 풀
HikariCP 사용
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/**
* HikariCP 커넥션 풀 사용
*/
@Test
void dataSourceConnectionPool() throws SQLException, InterruptedException {
// HikariCP 설정
HikariDataSource dataSource = new HikariDataSource();
dataSource.setJdbcUrl(URL);
dataSource.setUsername(USERNAME);
dataSource.setPassword(PASSWORD);
dataSource.setMaximumPoolSize(10); // 최대 커넥션 수: 10개
dataSource.setPoolName("MyPool");
useDataSource(dataSource);
Thread.sleep(1000); // 커넥션 풀 생성 대기
}
HikariDataSource도DataSource인터페이스를 구현- 최대 풀 사이즈는 10개로 설정
- 커넥션 풀 생성은 별도 쓰레드에서 진행됨
- 커넥션을 미리 만드는 작업은 시간이 걸림
- 애플리케이션 실행 시간에 영향을 주지 않도록 별도로 처리
커넥션 풀 상태 확인
1
MyPool - After adding stats (total=10, active=2, idle=8, waiting=0)
| 항목 | 설명 |
|---|---|
| total | 전체 커넥션 수 |
| active | 사용 중인 커넥션 |
| idle | 대기 중인 커넥션 |
| waiting | 대기 중인 요청 |
DataSource 적용
MemberRepositoryV1 구현
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/**
* DataSource를 활용한 MemberRepository
*/
@Slf4j
public class MemberRepositoryV1 {
private final DataSource dataSource;
public MemberRepositoryV1(DataSource dataSource) {
this.dataSource = dataSource;
}
private void close(Connection con, Statement stmt, ResultSet rs) {
JdbcUtils.closeResultSet(rs);
JdbcUtils.closeStatement(stmt);
JdbcUtils.closeConnection(con);
}
private Connection getConnection() throws SQLException {
Connection con = dataSource.getConnection();
log.info("get connection={}, class={}", con, con.getClass());
return con;
}
}
이전 코드와 달라진 점
DataSource를 외부에서 주입 받음(의존성 주입)- 리소스 정리 시 스프링의
JdbcUtils사용
실행 결과 비교
- DriverManagerDataSource 사용 시
1 2 3
get connection=conn0 get connection=conn1 get connection=conn2
- 매번 새로운 커넥션 생성함
- HikariDataSource 사용 시
1 2 3
get connection=HikariProxyConnection@xxx wrapping conn0 get connection=HikariProxyConnection@xxx wrapping conn0 get connection=HikariProxyConnection@xxx wrapping conn0
- 같은 커넥션(conn0)을 재사용함
HikariProxyConnection은 실제 커넥션을 감싸는 프록시 객체
DI의 장점
DriverManagerDataSource에서HikariDataSource로 변경해도DataSource인터페이스에만 의존하기 때문에MemberRepositoryV1코드는 전혀 수정할 필요 없음- 구현체만 갈아끼우면 됨 (의존성 주입 + 개방-폐쇄 원칙)
연습 문제
-
데이터베이스 연결을 매 요청마다 새로 맺는 방식의 비효율적인 측면은 무엇일까요?
a. 연결 설정 과정이 시간과 자원을 많이 소모해서
- 데이터베이스 연결 설정은 TCP/IP 통신, 인증, 세션 생성 등 복잡하며 매번 새 연결을 만들면 시간과 자원이 많이 낭비됨
- 이는 응답 속도 저하로 이어짐
-
데이터베이스 커넥션 풀의 주된 역할은 무엇일까요?
a. 데이터베이스 연결을 미리 만들고 재사용하는 역할
- 커넥션 풀은 애플리케이션 시작 시 미리 일정 개수의 연결을 만들어 관리하고, 필요할 때 빌려주고 사용 후 반납받아 재사용하는 역할을 함
- 연결 생성 오버헤드를 줄임
-
자바에서
javax.sql.DataSource인터페이스를 사용하는 주된 목적은 무엇일까요?a. 커넥션 획득 방식을 추상화하여 유연성을 확보하기 위해
DataSource인터페이스는getConnection()메서드를 통해 커넥션 획득 방법을 추상화함- 덕분에
DriverManager든 커넥션 풀이든 구현체 변경 시 애플리케이션 코드를 건드리지 않아도 됨
-
DataSource인터페이스를 사용할 때,DriverManagerDataSource에서 HikariCP와 같은 커넥션 풀로 변경해도 애플리케이션 비즈니스 로직 코드를 거의 수정하지 않아도 되는 이유는 무엇일까요?a. 애플리케이션 코드가 구체적인 구현체 대신
DataSource인터페이스에 의존하기 때문에- 애플리케이션 코드는
DataSource인터페이스에만 의존하도록 작성되기 때문 - 인터페이스의 구현체가
DriverManagerDataSource에서 HikariCP로 바뀌어도getConnection()호출 방식은 똑같음
- 애플리케이션 코드는
-
DriverManagerDataSource의getConnection()호출과 HikariCPDataSource의getConnection()호출 시, 커넥션 객체를 다루는 방식에서 가장 큰 차이점은 무엇일까요?a.
DriverManagerDataSource는 항상 새로운 연결을 생성하지만, HikariCP는 풀에서 기존 연결을 재사용함DriverManagerDataSource는getConnection()호출 시마다DriverManager를 이용해 실제 데이터베이스에 새 연결을 맺음- HikariCP는 미리 만들어 둔 풀에서 사용 가능한 연결을 가져와 재사용함
요약 정리
- 커넥션 풀이란?
- 애플리케이션 시작 시 커넥션을 미리 생성하여 풀에 보관하고, 필요 시 재사용하는 방식
- 커넥션 풀 장점
- 빠른 응답 속도
- 리소스 절약
- DB 보호
- 최대 커넥션 수 제한
- HikariCP
- 스프링 부트 2.0부터 기본 커넥션 풀
- 고성능과 안정성으로 실무 표준
- DataSource
- 커넥션 획득 방법을 추상화하는 표준 인터페이스 (
javax.sql.DataSource) - 핵심 메서드
Connection getConnection()
- 커넥션 획득 방법을 추상화하는 표준 인터페이스 (
- 설정과 사용 분리
- 객체 생성 시 한 번만 설정
- 이후
getConnection()만 호출
- DriverManagerDataSource
- 스프링이 제공하는
DriverManager래퍼 DataSource인터페이스 구현
- 스프링이 제공하는
- HikariDataSource
- HikariCP 커넥션 풀의
DataSource구현체
- HikariCP 커넥션 풀의
- 커넥션 풀 상태
- total (전체)
- active (사용 중)
- idle (대기)
- waiting (대기 요청)
- 별도 쓰레드
- 커넥션 풀 생성 시 애플리케이션 실행 속도에 영향 안 주기 위함
- 커넥션 반환
close()호출 시 종료가 아닌 풀에 반환- 살아있는 상태로 재사용
- JdbcUtils
- 스프링이 제공하는 JDBC 편의 메서드
- 리소스 정리 간편화
- 실무 권장
- 항상 커넥션 풀 사용
HikariCP권장DataSource인터페이스 의존