DB 커넥션을 획득할 떄 다음과 같은 과정을 거친다.
1. 애플리케이션 로직에 의해 DriverManger가 DB 드라이버를 조회해 커넥션을 조회한다.
2. DB 드라이버는 DB와 TCP/IP 커넥션을 연결한다. 이 과정에서 3 way handshake 같은 네이트워크 동작이 발생한다.
3. DB 드라이버는 TCP/IP 커넥션이 연결되면 ID,PW 부가 정보를 DB에 전달한다.
4. DB는 전달된 정보를 통해 내부 인증을 완료하고, 내부에 DB세션을 생성한다.
5. DB는 커넥션 생성이 완료되었다는 응답을 보낸다.
6. DB드라이버는 커넥션 객체를 생성해 애플리케이션 로직에 반환한다.
커넥션을 새로 만드는 과정은 복잡하고 시간이 많이 소요도니다.
DB는 물론이고, 서버에도 TCP/IP 커넥션을 생성하기 위한 리소스를 매번 사용해야 한다.
결과적으로 응답속도에 영향을 준다.
커넥션을 미리 만들어 두고 사용하는 방법을 커넥션 풀이라고 한다.
커넥션 풀은 커넥션을 관리하는 풀이다.
앱이 시작하는 시점에 커넥션 풀은 필요한 만큼 커넥션을 미리 확보해서 풀에 보관한다.
커넥션 풀에 들어 있는 커넥션은 TCP/IP로 DB와 커넥션이 연결되어 있는 상태이기 때문에 언제든지 즉시 SQL을 DB에 전달할 수 있다.
사용할 때는 객체참조로 사용할 수 있고, 사용한 후에 커넥션을 닫지 않고 커넥션 풀에 반환을 해줘야 한다.
이제 커넥션을 사용하는 방법은 JDBC의 DriverManager를 직접 사용하거나 커넥션풀을 사용하는 방법이 있다는 것을 알 수 있다.
DriverManger를 직접 사용하는 방법은 매번 커넥션을 생성해 획득하는 방법이다.
(커넥션 풀 또한 내부적으로 DriverManger를 사용한다.)
커넥션을 획득하는 방법을 추상화한 것이 DataSource 인터페이스 이다.
핵심 기능은 커넥션 조회 이다.
@Test
void driverManager() throws SQLException {
Connection con1 = DriverManager.getConnection(URL, USERNAME, PASSWORD);
Connection con2 = DriverManager.getConnection(URL, USERNAME, PASSWORD);
log.info("connection1={} class={}", con1, con1.getClass());
log.info("connection2={} class={}", con2, con2.getClass());
}
@Test
void driverMangaerDataSource() 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("connection1={} class={}", con1, con1.getClass());
log.info("connection2={} class={}", con2, con2.getClass());
}
DriverMangaerDataSource : 객체를 생성할 때만 설정정보를 필요로 한다.
DriverManager : 커넥션을 얻어올 때마다 설정정보를 필요로 한다.
설정과 사용의 분리
애플리케이션을 개발하면 보통 설정은 한 곳에서 하지만, 사용은 수많은 곳에서 하게 된다.
덕분에 객체를 설정하는 부분과 사용하는 부분을 더 명확히 분리해 향후 변경에 유연하게 대처할 수 있다.