- 어플리케이션 로직은
DB Driver
를 통해 Connection을 조회DB Driver
는 TCP/IP로 DB와 커넥션 연결 (이 과정에서 3-way handshake와 같은 동작이 발생한다.)DB Driver
는 USERNAME/URL/PW 와 같은 부가정보를 DB에 전달한다.- DB는 부가 정보를 바탕으로 내부 인증을 완료하고, DB 세션을 생성한다.
- DB는
DB Driver
에게 커넥션 생성 완료 응답을 전송한다.DB Driver
는 커넥션 객체를 생성해서 클라이언트에게 반환한다.
위 과정처럼 커넥션을 생성하면서 획득하는 과정으 복잡하고 비용도 많이 든다. 만약 웹 서버에서 DB에 접속할 때마다 위와 같은 과정이 일어나면 비효율적이다.
이를 해결하기 위해 Connection Pool
의 개념이 나왔다.
Connection Pool
은 필요한 만큼 Connection
을 미리 확보해서 Pool에 보관하는 방식DB Driver
를 통해 매번 새로운 Connection
을 획득하는 것이 아닌, Connection Pool
에서 이미 연결되어 있는 커넥션을 꺼내 쓴다.Connection
사용 후 종료하는 것이 아닌, 다음에 다시 사용할 수 있도록 Connection Pool
에 반환한다.
- 각 어플리케이션마다의
Connection Pool
의Connection
개수는 서버 스펙, DB 스펙에 따라 다르기 때문에, 성능 테스트를 통해서 결정해야한다.- 대표적으로는
commons-DBCP2
tomcat-jdbc pool
HicariCP
등이 있고, Spring 2.0 부터는 기본으로HicariCP
를 제공한다.
위 그림과 같이 DB Connection을 획득하기 위해서는 생성 방식
Connection Pool 방식
등이 있다.
하지만 만약 기존에 DriverManager
로 커넥션 생성 방식을 사용하고 있다가, DBCP2
나 HikariCP
와 같은 Pool 방식으로 교체한다고 하면, 많은 어플리케이션 코드도 수정되어야 할 것이다.
이러한 문제를 해결하기 위해, DataSource
가 등장한다!!
위 그림과 같이, DBCP2
HikariCP
DriverManager
등 Connection 획득 방법을 추상화한다면, 어떤 Connection 획득 방법을 사용하든지 상관 없다. 왜냐하면 우리는 DataSource
라는 추상화된 인터페이스에만 의존하면 되기 때문이다.
public interface DataSource extends CommonDataSource, Wrapper {
Connection getConnection() throws SQLException;
}
javax.sql.DataSource
라는 인터페이스를 제공DataSource
에는 Connection을 반환하는 getConnection()
메소드가 존재DBCP2
HikariCP
에 직접 의존하는 것이 아닌, DataSource
인터페이스에만 의존사실 DriverManager
는 DataSource
인터페이스를 사용하지 않는다. 그렇다면 어떻게 DriverManager
를 사용하는 DataSource
의 구현체는 무엇일까?
바로 DriverManager
도 DataSource
를 통해 사용할 수 있도록 DriverManagerSource
라는 클래스가 존재한다.
정리하자면, DriverManagerDataSource
를 통해서 DriverManager
를 사용하다가 HikariCP
를 사용하더라도 애플리케이션 로직은 변경하지 않아도 된다!!
/* DriverManager를 통한 Connection 획득 */
@Test
void driverManager() throws SQLException {
Connection con1 = DriverManager.getConnection(URL, USERNAME, PASSWORD);
Connection con2 = DriverManager.getConnection(URL, USERNAME, PASSWORD);
}
/* DriverManagerDataSource를 통한 커넥션 획득 */
@Test
void dataSourceDriverManager() throws SQLException {
DataSource 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());
}
DriverManagerDataSource
내부에서 DriverManager
사용DriverManager
는 getConnection()
을 통해 커넥션을 획득할 때마다 URL, USERNAME, PASSWORD와 같은 파라미터를 계속 넘겨주어야 한다DriverManagerDataSource
는 처음 객체를 생성할 때만 파라미터를 넘겨주고, 커넥션을 획득할 때는 dataSource.getConnection()
만 호출위 코드처럼
DriverManagerDataOusrce
는 사용과 설정을 분리했다. 이로써Repository
는DataSource
만 의존하고, 사용 설정을 모른 상태로getConnetion()
만 사용하면 된다.