들어가며
- 저번 포스트에서 커넥션 풀에 대해 알아보았다.
- 이번 포스트에는 해당 커넥션 풀을 사용하는데 있어 사용하는 추상화된 인터페이스인 DataSource 인터페이스에 대해 알아본다.
DataSource
- 지금까지 우리가 구현한 예제에서 커넥션을 얻을 때는 DriverManager.getConnection()을 사용하였다. 그런데 이제 DriverManager를 통해 계속 커넥션을 새로 생성하는게 아니라 커넥션 풀을 사용하여 커넥션을 얻으려고 한다.
- 문제는 각 커넥션 풀을 사용하는 방법들이 모두 다를 수 있단 것이다. 즉 구체적인 방법에 애플리케이션이 의존할 수 있다.
- 만약 커넥션 풀 1을 사용하는데 커넥션을 가져오는 코드가 getConnection()이라고 하자. 그런데 커넥션 풀 2로 바꾸어야 하는 상황인데 커넥션 풀 2의 커넥션을 가져오는 코드가 get() 이라면? 결국 모든 코드를 변경해야 하는 상황이 올 것이다.
- 결국 어떤 커넥션 풀을 사용하는지에 따라 코드에 많은 변경이 가해지는 것이고 이는 결코 좋지 않은 신호이다.
- 이러한 문제를 해결하기 위해서 DataSource라는 인터페이스가 등장했다.
- DataSource는 커넥션을 얻는 방법을 추상화 하는 것으로 각 커넥션 풀 클래스들이 해당 인터페이스를 구현함으로서 커넥션을 가져오는 방식을 통일할 수 있다. 만약 커넥션 풀을 바꾸어야 하는 상황이 오더라도 구현 클래스만 갈아끼우면 된다.
- 문제점이 하나 더 있는데 DriverManager 클래스를 보면 DataSource 를 구현하고 있지 않다. 따라서 DriverManager 클래스를 사용할 시 코드가 변경될 수 있다.
- 이를 해결하기 위해 DataSource를 구현한 DriverManager인 DriverManagerDataSource 클래스를 제공하고 있다.
DataSource를 통한 커넥션 풀 얻기
DriverManagerDataSource
- DriverManagerDataSource를 사용한 커넥션 풀 얻기를 한번 구현해 보자.
@Slf4j
public class UseConnectionPool{
void dataSourceDriverManager() throws SQLException{
DriverManagerDataSource dataSource = new DriverManagerDataSource(URL, USERNAME, PASSWORD);
useDataSource(dataSource);
}
private void useDataSource(DataSource dataSource) throws SQLException{
Connection conn1 = dataSource.getConnection();
Connection conn2 = dataSource.getConnection();
log.info("connection = {}, class = {}", conn1, conn1.getClass());
log.info("connection = {}, class = {}", conn2, conn2.getClass());
}
}
- DriverManager에서는 항상 getConnection에서 URL, USERNAME, PASSWORD를 넣어주어야 했다. DataSourceDriverManager에서는 생성할 때 단 한번 사용되며 그 이후에는 사용하지 않아도 된다.
HikariCP
- HikariCP를 사용하여 커넥션을 얻어보도록 하자.
@Slf4j
public class UseDataSourceConnection{
private final HikariDataSource dataSource;
UseDataSourceConnection(){
dataSource = new HikariDataSource();
dataSource.setJdbcUrl(URL);
dataSource.setUsername(USERNAME);
dataSource.setPassword(PASSWORD);
dataSource.setMaximumPoolSize(10);
dataSource.setPoolName("My Pool");
Thread.sleep(1000);
}
public void useDataSource() throws SQLException{
Connection conn1 = dataSource.getConnection();
Connection conn2 = dataSource.getConnection();
log.info("connection = {}, class = {}", conn1, conn1.getClass());
log.info("connection = {}, class = {}", conn2, conn2.getClass());
}
}
- 설정할 것이 꽤 있는데 Url, Username, Password는 연결할 DB의 주소, ID, PW를 통해 인증을 수행해야 해서 그렇다. setMaximumPoolSize는 커넥션 풀의 최대 커넥션 개수이다.
- Thread를 sleep하여 잠시 대기하도록 한 것은 커넥션 풀의 초기화 과정에서 다른 스레드를 사용하기 때문이다.
- 커넥션 풀은 애플리케이션이 실행될 때 초기화되는데 만약 커넥션 풀의 용량이 매우 큼으로 인해 커넥션 풀 최화에 시간이 많이 들어가는 경우를 고려하여 별개의 스레드를 할당하여 수행하도록 하고 있다.
- 즉 애플리케이션이 초기화되는 스레드와 커넥션 풀의 초기화를 담당하는 스레드는 별개의 스레드이다. 그런데 지금 로직은 어플리케이션의 초기화 속도가 너무 빠르기 때문에 커넥션 풀이 다 초기화되지 않은 상태에서 호출하는 상황이 일어날 수 있으므로 일부러 어플리케이션의 초기화 속도를 늦춘 것이다.
- 로그를 통해 현재 사용되고 있는 커넥션이 몇 개고, 여유분이 몇 개인지도 확인이 가능하다.
정리
- 지금까지 커넥션 풀의 개념과 DataSource를 사용하여 커넥션 풀을 자바에서 어떻게 사용하는지를 알아보았다.
- 다음 포스트에서는 이전에 만들었던 레포지토리를 DataSource를 사용하여 커넥션 풀을 사용하도록 구현해본다.
'Spring & JPA > JDBC' 카테고리의 다른 글
JDBC - JDBC 커넥션 풀 - DataSource 적용 (0) | 2023.06.05 |
---|---|
JDBC - JDBC 커넥션 풀 - 커넥션 풀의 개념 (0) | 2023.06.05 |
JDBC - JDBC 사용 - 3. 데이터 수정과 삭제 (0) | 2023.06.03 |
JDBC - JDBC 사용 - 2. 데이터 조회 (0) | 2023.06.03 |
JDBC - JDBC사용 - 1. 데이터 저장 (0) | 2023.06.03 |