[JDBC] DBCP (Database Connection Pool)
DBCP (Database Connection Pool)
DBCP란 미리 일정량의 DB 커넥션을 생성해 풀에 저장해 두고 있다가 HTTP 요청에 따라 필요할 때 풀에서 커넥션을 가져다 사용하는 기법을 말한다. 참고로 Spring Boot 2.0 부터는 Default DBCP로 HikariCP를 사용하고 있다.
이러한 Connection Pool 사용할 때 고려해야 할 몇 가지 사항이 있다. 먼저 커넥션 사용 주체는 WAS 스레드이므로 커넥션 개수는 WAS 스레드 수와 함께 고려해야 한다. 여기서 WAS 스레드는 요청을 처리하기 위해 main 스레드 내부 스레드 풀에서 생성해 할당하는 스레드를 말한다.
가령, 커넥션 수를 크게 설정하면 메모리 소모가 큰 대신 동시 접속자 수가 많아지더라도 사용자 대기 시간이 상대적으로 줄어들게 된다. 반대로 커넥션 보유 수를 작게 설정하몀 메모리 소모는 적은 대신 대기 시간이 길어질 수 있음을 알아야 한다. 따라서 성능 최적화를 위해서는 적정량의 커넥션 객체를 생성해 두는 것이 중요하다.
이러한 커넥션을 획득하기 위해서는 DataSource라는 커넥션 획득을 위한 Java 표준 인터페이스를 사용한다. 데이터베이스 표준 구현체들을 사용해본 개발자라면 xml이나 yaml 파일에 가장 먼저 설정해주었던 것이 DataSource였을 것이다. 아래에는 H2 Database를 통해 JDBC 실습과 JDBC 코드 리팩토링, DB 커넥션 풀 적용 방법을 간단하게 정리해 놓는다.
JDBC 프로그래밍 실습
JDBC 프로그래밍 실습에서는 사용자 ID, 비밀번호, 이름, 이메일 정보를 가지는 사용자 객체를 생성하고 영속성을 부여하는 간단한 작업을 진행해본다. 이 때, 사용자 객체와 DB에 접근하는데 사용되는 접근 객체를 분리해 구현한다. 여기서 접근에 사용되는 객체를 DAO(Database Access Object)라고 한다.
먼저 DAO를 생성하는 테스트를 아래와 같이 작성한다. 이 때, db_schema.sql에는 간단한 테이블 생성 쿼리를 작성해 놓는다. 그리고 HikariDataSource을 사용하는 ConnectionManager 클래스로부터 DataSource를 반환 받는다.
위 테스트에서는 사실 두 가지 메소드를 동시에 테스트한다. 하나는 create(), 다른 하나는 findByUserId()이다. 먼저, UserDao는 User 객체를 전달 받아 create() 메소드를 통해 테이블에 저장한다. 그리고 저장했던 객체를 ID를 통해 그대로 가져와 같은지 비교한다. 이 일련의 테스트를 수행하는 각 메소드들을 자세히 살펴보면 아래와 같다. 중요한 것은 connection을 얻고, PreparedStatement를 준비하고, ResultSet을 통해 조회한 결과를 받아오고, 각 연결을 순차적으로 끊어주는 과정들을 개발자가 모두 수동으로 작성해야 한다는 것이다.
Refactoring: Connection 관리
Refactoring Target은 많지만 DBCP와 관련된 부분은 바로 UserDao에서 직접 호출해 얻어와 사용하던 Connection Pool을 ConnectionManger에서 관리하도록 변경하는 것이다. 앞서 보았던 getConnection() 메소드 내부 로직을 ConnectionManager에 위임하고, 한 개 스레드에서만 호출할 수 있도록 변경 가능하다.
여기에 더해 SQL 적용 과정에서 JdbcTemplate에 활용된 패턴을 적용하는 것과 같은 리팩토링 포인트가 존재한다. 핵심은 공통으로 사용하는 부분을 분리하고, 변화하는 부분을 인터페이스로 정의하고 구현을 위임하여 의존성이 분리되는 것을 지향하는 것이다.
Leave a comment