JDBC와 DB 커넥션 풀

이수찬·2023년 4월 3일
1

1. JDBC 등장 이유

기존적으로 애플리케이션 서버가 db를 사용하려면

  1. 커넥션 연결(주로 tcp/ip통신)
  2. sql 전달
  3. DB는 전달된 sql을 실행하고, 서버에 결과 응답순으로 진행된다.

  • 문제는 각각의 데이터베이스 마다 1,2,3의 방법이 모두 다르다는 점이다.
  • 이를 해결하기 위해 JDBC라는 java api가 만들어졌다.
  • java는 JDBC라는 표준 인터페이스를 통해, 구체적인 데이터베이스에 의존하지 않고, 인터페이스 사용법만 익혀도 여러 데이터베이스를 사용할 수 있도록 만들었다.

특정 db에 접근할 수 있는 것을 드라이버라 하는데, 어떤 db든 접근할 수 있는 java 표준 드라이버를 JDBC driver라고 한다.

  • 그림을 보면 애플리케이션 로직은 JDBC 표준 인터페이스에만 의존하며, 데이터베이스를 변경하고 싶다면, JDBC 구현 라이브러리만 변경하면 된다는 것을 알 수 있다.
  • 개발자는 데이터베이스마다 다른 커넥션 연결, sql전달, 결과를 응답받는 방법을 모두 학습할 필요없이, JDBC 표준 인터페이스의 사용법만 학습하면 된다.
  • 그러나 이런 JDBC 표준 인터페이스에도 한계가 존재하는데, 각각의 데이터베이스에는 sql과 데이터 타입등의 일부 사용법들이 다르다.

이때 자바 진영에서는 JPA를 사용하면 각각 데이터베이스마다 다르게 sql을 정의해야 했던, 문제를 대부분 해결할 수 있다.
ORM 기술중 하나인 JPA가 개발자 대신에 SQL을 동적으로 만들어
실행해준다. 추가로 각각의 데이터베이스마다 다른 SQL을 사용하는 문제도 중간에서 해결해준다.


2. JDBC 커넥션 인테페이스와 구현

Driver Manager의 connection 요청 흐름

  1. 애플리케이션 로직의 커넥션 요청
  2. JDBC가 관리하는 DriverManager가 getConnection을 통해 url, 이름, 비밀번호 등 접속에 필요한 정보들을 라이브러리에 넘겨 등록된 드라이버 목록에서 다음 정보들을 처리할 수 있는 드라이버를 찾는다.
  3. 드라이버가 제공하는 커넥션을 클라이언트에 반환한다.

3. 커넥션 풀

커넥션 풀의 도입 배경

다음은 데이터베이스 커넥션의 획득 과정이다.

  1. 애플리케이션 로직은 db driver을 통해 connection을 조회한다.
  2. db driver는 db와 tcp/ip 통신으로 tcp/ip 커넥션을 연결한다.
  3. db driver는 tcp/ip 커넥션을 연결하면 데이터베이스 접속에 필요한 정보들을 db에 전달한다.
  4. db는 받은 정보들로 인증을 완료하고, 내부에 db세션을 생성한다.
  5. db는 커넥션이 생성이 완료되었다는 응답을 보낸다.
  6. db driver는 커넥션 객체를 생성해 클라이언트에 반환한다.
  • 이렇게 커넥션을 새로 만드는 일은 복잡하며, 매번 리소스를 사용해야 하기에 비용도 많이 드는 일이다.
  • 또한 애플리케이션 사용시 sql을 실행할 때 커넥션을 새로 만드는 시간이 추가되기에 응답속도가 추가적으로 느려진다.

커넥션 풀 이해하기

  • 매번 커넥션을 새로 생성해 연결하는 문제를 한번에 해결하기위해 커넥션을 미리 생성해두고, 사용하는 것을 커넥션 풀이라 한다.

  • 커넥션 풀에 있는 커넥션은 tcp/ip통신으로 db와 커넥션이 연결되어 있는 상태이기 때문에 sql을 db로 전달할때, 새로 커넥션을 맺을 필요없이 연결되어 있는 커넥션을 사용하여 sql을 전달한다.

  • 이제 애플리케이션 로직은 db 드라이버를 통해 새로운 커넥션을 획득하는것이 아닌, 커넥션 풀을 통해 이미 생성되어 있는 커넥션을 객체 참조로 그냥 가져다 쓰면 된다.

  • 커넥션을 모두 사용하고 나면 jdb driverManager에서 커넥션을 종료한것과 달리 해당 커넥션을 그대로 커넥션 풀에 반환하면 된다.

  • 참고) 대표적인 커넥션풀로는 HikariCP와 tomcat-jdbc-pool등이 있는데,
    spring boot 2.0부터는 기본 커넥션 풀로 HikariCP를 사용한다.

  • 이제 커넥션 풀을 획득하는 방법으로는 JDBC driver manager을 사용하거나,
    커넥션 풀을 이용하는 등 다양한 방법이 존재한다는 것을 알았다.

  • 그런데 만약 driver manager를 사용하다가, HikariCP같은 커넥션 풀을 사용하면 어떻게 될까?
    그렇게 되면, 커넥션을 획득하는 애플리케이션 코드를 변경해야 한다.


4. DataSource 이해하기

  • 이런 문제를 해결하기 위해 자바는 커넥션을 획득하는 방법을 추상화한 datasource라는 인터페이스를 제공한다.

  • 참고) DataSoucrce는 DriverManager 인터페이스를 사용하지 않기에
    datasource를 사용하여 drivermanager를 사용하고 싶다면,
    driverManagerDataSource라는 datasource를 구현한 클래스를 사용해야 한다.
    물론, DriverManagerDataSource는 커넥션 풀을 사용하지 않기에 항상 새로운 커넥션이 생성된다.

  • Java는 커넥션을 획득하고 싶다면, Datasource 인터페이스에만 의존하면 된다. 커넥션 풀 구현 기술을 변경하고 싶다면, 해당 구현체로 갈아끼우기만 하면 된다.

  • 커넥션 풀에서 커넥션을 생성하는 작업은 애플리케이션 실행 속도에 영향을 주지 않기 위해 별도의 쓰레드에서 작동한다.

  • 커넥션 풀에 커넥션을 채우는 작업은 시간이 오래걸리기 때문에, 커넥션 풀을 채우는것과 별개로 쓰레드를 사용하여 어플리케이션이 실행시킨다.


DataSource의 설정과 사용 분리

DriverManager 는 커넥션을 획득할 때 마다 URL , USERNAME , PASSWORD 같은 파라미터를 계속 전달해야 한다.

Connection connection = DriverManager.getConnection(URL, USERNAME, PASSWORD);

반면에 DataSource 를 사용하는 방식은 처음 객체를 생성할 때만 필요한 파리미터를 넘겨두고, 커넥션을 획득할 때는 단순히 dataSource.getConnection() 만 호출하면 된다.

DriverManagerDataSource dataSource = new DriverManagerDataSource(URL,
USERNAME, PASSWORD);
Connection connection = datasource.getConnection();

설정

DataSource는 생성자를 통해 생성할 때, 매개변수에 URL, USERNAME, PASSWORD를 설정해 설정을 한 곳에 모아 놓았다.

사용

설정은 신경쓰지 않고, DataSource 의 getConnection() 만 호출해서 Connection을 사용할 수 있다.

설정과 사용의 분리

필요한 데이터를 DataSource 가 만들어지는 시점에 미리 다 넣어두게 되면, DataSource 를 사용하는 곳에서는 dataSource.getConnection() 만 호출하면 되므로, URL , USERNAME , PASSWORD 같은 속성들에 의존하지 않아도 된다. 그냥 DataSource 만 주입받아서 getConnection() 만 호출하면 된다. 이를 통해 설정을 한 곳에서만 관리하여, 유지 보수가 훨씬 편리해졌다.

<참고자료> : 스프링 DB 1편 - 데이터 접근 핵심 원리
https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-db-1

0개의 댓글