개요
기존에 커넥션을 얻기 위해 JDBC 구현체를 DriverManager로 찾던 전통적인 방법의 한계점과 대안을 알아보겠습니다. Connection Pool과 DataSource 중심 코드의 구성과 성능 개선을 확인해보겠습니다
전통적 Jdbc DriverManger의 문제점
기존 DriverManager는 커넥션이 필요할 때마다 새롭게 생성하고 작업이 끝나면 해제하는 작업을 반복했습니다. 커넥션을 연결하고 종료하는 작업이 가볍지 않기 때문에 매 요청마다 커넥션을 만드는 것은 리소스가 많이 필요하고 시간이 걸리는 작업이라는 한계가 있었습니다.
그래서 커넥션 풀이라는 기술이 등장했습니다.
커넥션 풀(Connection pool)
커넥션 풀이란, 미리 커넥션을 풀에 담아두어서 커넥션이 필요할때마다 꺼내어주는 장소입니다.
매번 커넥션을 생성하고 종료시켰던 직접적인 jdbc DriverManger 연결과 달리 커넥션 풀은 애플리케이션을 시작하는 시점에서 필요한만큼 커넥션을 확보합니다. 따라서 초기화 이후 애플리케이션 서버 내부에서 커넥션 획득이 가능하며, 사용이 끝나면 커넥션을 종료하는게 아니라 다시 커넥션 풀에 반납해서 다음 번 요청 시 사용할 수 있도록 합니다.
커넥션 풀 안에서 커넥션들은 DB와 미리 TCP/IP로 연결이 되어있기 때문에, 언제든지 DB로 SQL을 전달할 수 있습니다.
대표 기술 : commons-dbcp2 , tomcat-jdbc pool , HikariCP
(참고로 스프링 부트 2.0부터는 기본 커넥션 풀로 hikariCP을 사용하는데, 가장 성능이 뛰어납니다.)
이제 애플리케이션은 더이상 DriverManager를 통해서 커넥션을 획득하지 않습니다. 이미 커넥션 풀에 생성된 커넥션 객체 참조로 가져다가 씁니다. 사용하고 나면 커넥션을 종료하지 않고 커넥션 풀에 다시 반납합니다.
아래 사진처럼, 커넥션을 획득하는 방법은 DriverManager 혹은 커넥션 풀을 사용하는 것입니다.
DriverManager로 매번 신규 커넥션을 생성하는 것보다 미리 커넥션 풀에 준비된 커넥션을 사용하는 것이 훨씬 편합니다.
어떻게 하면 커넥션을 효과적으로 쉽게 획득할 수 있는지 DataSource를 통해 알아보겠습니다.
DataSource의 이해
DataSource는 커넥션을 획득하는 방법을 추상화 한 것입니다.
자바는 javax.sql.DataSource 인터페이스를 통해서 커넥션을 얻는 방법을 추상화하였고 구현체에 따라서 다양한 방식으로 커넥션을 획득할 수 있습니다. 아래에 대표적으로 DBCP2 , HikariCP, DriverManagerDataSource 등이 있습니다. getConnection()을 추상화했기 때문에, 각 상황에 맞는 구현체로 쉽게 변경이 가능합니다.
위의 코드는 DataSource 인터페이스 입니다. 가장 중요한 것은 getConnection()을 추상화하고 있다는 것입니다.
아래의 코드는 DataSource를 사용해서 커넥션을 얻고 있습니다. 생성자 주입에서 매개변수로 받기 때문에, DataSource 구현체만 만들어주면 자동으로 주입받습니다.
또한 아래의 코드에서 Connection, Statement, ResultSet을 close하는 과정을 JdbcUtils를 이용해서 합니다. 길게 정의하였던 코드들이 JdbcUtils 라는 라이브러리 기능에 포함되어 짧게 줄었습니다.
아래의 코드에서 DataSource를 이용하여 데이터베이스에 연결하는 것을 테스트 합니다. 먼저, HikariDataSource 객체를 만들고, URL, USERNAME, PASSWORD를 설정하고 생성 시 매개변수에 넣었습니다. 기본 10개의 커넥션 풀이, 애플리케이션이 실행될 때 데이터베이스와 TCP/IP연결이 되어 커넥션 풀에서 대기하고 있는 상태가 됩니다.
특히, 커넥션 풀이 좋은 것은 커넥션 사용이 다 끝나면 커넥션을 닫아버리는 것이 아니라 커넥션 풀에 다시 반납합니다. 따라서, 여러개의 작업이 있을 때 매번 커넥션을 생성하는 것이 아니라 기존의 커넥션을 재활용 할 수 있습니다.
아래는 히카리 커넥션 풀(HikariDataSource)을 사용했을 때, 커넥션 정보입니다. conn0이 계속 사용, 반환을 반복하며 다른 커넥션은 대기중입니다.
아래는 DriverManger.getConnection()을 사용했을 때, 커넥션 정보입니다. 작업이 있을 때마다 새로운 커넥션을 생성하고 반납합니다.
*참고
스프링 DB 1편 - 데이터 접근 핵심 원리(김영한님 강의)
'학습 > DB' 카테고리의 다른 글
hash join (0) | 2022.10.10 |
---|---|
인덱스 스캔 7가지 종류 (0) | 2022.10.08 |
JDBC 의 역사 (0) | 2022.09.01 |
DB의 인덱스와 B-tree, B+tree (0) | 2022.08.24 |
낙관적 잠금과 비관적 잠금으로 동시성 해결하기 (0) | 2022.08.19 |