SQL 을 날리기 위해 DriverManager 로 매번 Connection 을 얻어오는 것은 성능상 이슈가 있을 수 있다. 왜냐하면 Connection 을 얻어오기 위해서는 TCP 연결 하고, DB 에 한번은 갔다와야하기 때문이다. 때문에 일반적인 경우에는 미리 여러개의 Connection 들을 얻어와 이들을 모아둔 Connection Pool 이라는 개념을 사용한다.
따라서 SQL 을 날릴때마다 매번 Connection 을 얻어오지 않고, Connection Pool 에서 관리되는 Connection 을 가져와 즉시 SQL 을 날릴 수 있게 된다. 이렇게 사용된 Connection 은 종료되지 않은 상태 로 Connection Pool 로 다시 반환되게 되는데, 이 반환된 커넥션은 Connection Pooling(재사용) 된다.
오픈소스 Connection Pool
대표적인 오픈소스 Connection Pool 에는 commons-dbcp2, tomcat-jdbc pool, HikariCP 가 있다. 하지만 Spring 에서는 HikariCP 를 디폴트로 사용하고 있다.
DataSource
DriverManager 로부터 Connection 을 매번 가져오는 기존 방식에서 HikariCP 로부터 미리 생성된 Connection 을 가져오는 방법으로 바꾸려면, 의존관계를 DriverManager 에서 HikariCP 로 변경해야 한다.
즉, 기존 코드를 변경해야 한다는 건데.. 이를 불편하게 생각했던 Java 진영에서는 DB 로부터 Connection 을 가져오는 방법에 대한 추상화 를 하게 된다. 그리고 그 추상화에 대한 결과로 javax.sql.DataSource 라는 Interface 를 제공하게 된다. 따라서 개발자는 DataSource 를 구현하고 의존관계를 DataSource 로 바꾸면 OCP(Open Closed Principal : 개방 폐쇄 원칙) 를 지킬 수 있게 된다.
Note
처음부터 DataSource 에 의존하고 있었다면 상관없지만, 만약 기존에 DriverManager 를 직접 의존하고 있었다면 DataSource 로 의존관계 변경하기 위한 코드 수정은 피할 수 없다.
DataSource 구조
DataSource 에서 제일 중요한 부분은 Connection getConnection() 이다. 해당 메서드가 실제적으로 Connection 을 얻어오는 역할을 한다.
Note
DataSource 는 Connection 을 가져오는 방법을 추상화한 것이다. 따라서 Connection Pool 로부터 미리 저장된 Connection 을 가져오도록 구현할 수 있고, 아니면 똑같이 DriverManger 처럼 매번 Connection 을 가져오도록 구현할 수 있다.
Spring DataSource
Spring 에서 기본으로 제공하는 DataSource 는 크게 HikariDataSource , DriverManagerDataSoucre 가 있다. 모두 DataSource 를 구현하고 있는 것을 볼 수 있다.
Note
DataSource 의 구현체들은 객체를 생성할 때 한번만 URL, USER, PASSWORD 를 지정해주면 된다. 이는 설정과 사용을 분리시킴으로서, 후에 변경이 발생했을 떄 유연하게 대처할 수 있게 된다.
HikariDataSource
HikariDataSource 은 Spring 에서 기본으로 채택하고있는 DataSource 이다. getConnection() 을 하게 되면 Hikari Connection Pool 에서 Connection 을 가져오게 된다. 또한, HikariDataSource 는 내부적으로 Connection Pool 에서 Connection 을 가져오기 때문에, Pool 에 생성 및 보관할 수 있는 최대 Connection 개수(Pool Size)와 Pool 이름을 지정할 수 있다.
Thread.sleep() 을 넣어주어야 Connection 들이 만들어지고 Pool 에 저장되는 로그를 끝까지 볼 수 있다.
로그를 위해 logback.xml 를 작성하고 테스트 코드를 실행해보면 매우 긴 로그를 볼 수 있다.
4 번째 라인을 보면 우선 main 스레드에서 Connection 을 하나 만들고 Connection Pool 에 집어넣는 것을 볼 수 있다. 이 부분을 제외한 나머지 부분들은 풀 이름 + connection adder 이름의 별도의 스레드가 Connection 을 만들고 Pool 에 넣는 것을 볼 수 있다. 또한, Application 이 시작될 때, 사전에 설정한 Pool Size 만큼 Connection 들을 미리 생성하고 Pool 에 저장하는 것을 알 수 있다.
마지막으로 작성했던 테스트코드에서 찍은 로그를 보면 Connection 의 타입이 HikariProxyConnection@주소 wrapping 인 것을 볼 수 있다. 해당 의미는 HikariProxyConnection 안에 Wrapping 된 진짜 Connection 이 있다는 것이다.
DriverManagerDataSource
DriverManagerDataSource 는 Spring 에서 DriverManager 를 사용해서 구현한 DataSource 이다. DriverManger 는 Connection Pool 을 사용하여 Connection 을 관리하는 방식이 아니기 때문에, 매번 Connection 을 얻어오게 된다.
AbstractDriverBasedDataSource
DriverManagerDataSource
로그를 보면 매번 Connection 을 생성하여 가져오는 것을 확인할 수 있다.
정리
DataSource 는 Connection 을 가져오는 방법을 추상화 한 것.
Spring 의 기본 구현체는 HikariDataSource, DriverManagerDataSource 가 있으며 디폴트로 HikariDataSource 를 사용한다.
HikariDataSource 는 Connection Pool 에서 Connection 을 관리하고, Pool 에서 Connection 을 가져온다.
Application 이 시작될때 Pool Size 만큼 Connection 들을 미리 생성하고 Pool 에 저장시킨다.
DriverManagerDataSource 는 Connection 을 매번 새롭게 가져온다.