본문 바로가기

JAVA

[DB] JDBC, Connection Pool, Datasource 이해

과거에는 애플리케이션이 데이터베이스에서 데이터를 가져오는 과정이 커넥션을 생성하고 SQL을 전달, 그리고 결과를 응답받는 3단계에 걸쳐 이루어졌다.


그러나 이런 방식에는

  1. 데이터베이스를 다른 종류로 변경할 경우 애플리케이션 서버의 데이터베이스 관련 소스코드도 변경해야 한다.
  2. 개발자가 각각의 데이터베이스 종류마다 커넥션 연결, SQL 전달, 결과를 응답받는 방법을 새롭게 학습해야 한다.

와 같은 불편함이 있었고, 이에 따라 JDBC 라는 자바 표준이 등장하게 되었다.

JDBC (Java Database Connectivity)

  • 자바에서 데이터베이스에 접속할 수 있도록 하는 자바 API
  • 데이터베이스에서 자료를 쿼리하거나 업데이트하는 방법을 제공

JDBC 표준 인터페이스

  1. java.sql.Connection : 연결
  2. java.sql.Statement : SQL을 담은 내용
  3. java.sql.ResultSet : SQL 요청 응답

위 3가지 기능을 표준 인터페이스로 정의하여 제공.

이를 각각의 DB 벤더에서 당사의 DB에 맞도록 구현하여 제공하는 라이브러리를 JDBC Driver라고 한다


장점

  • 애플리케이션 로직이 JDBC 표준 인터페이스에만 의존하여 데이터베이스의 종류를 변경해도 애플리케이션 서버의 코드 변경 없이 JDBC Driver만 변경하면 된다
  • 개발자는 각각의 데이터베이스 사용법을 학습할 필요 없이 JDBC 표준 인터페이스 사용법만 학습하면 된다
  • 한계
    • 표준화로 JDBC 코드는 변경할 필요가 없어졌으나, 각각의 데이터베이스마다 SQL, 데이터타입 등 일부 사용법의 차이로 SQL 구문은 알맞게 변경해야 한다
    • 그러나 이러한 불편 역시 JPA(Java Persistence API)의 등장으로 많은 부분 해결되었다

JDBC와 최근 데이터 접근 기술

  1. SQL Mapper
    • 대표 기술 : Spring JDBC Template, MyBatis
    • 애플리케이션 로직이 SQL Mapper에 SQL을 전달하면 이를 SQL Mapper이 JDBC에 전달
    • 장점
      • SQL 응답 결과를 객체로 편리하게 변환
      • JDBC의 반복코드를 제거
    • 단점
      • 개발자가 SQL을 직접 작성해야 한다
  2. ORM 기술
    • 대표 기술 : JPA, Hibernate, Eclipse Link
    • 애플리케이션 로직이 JPA에 객체를 전달하면 이를 JPA의 구현체가 SQL로 변환하여 JDBC에 전달
    • 객체를 관계형 데이터베이스 테이블과 매핑해주는 기술. ORM 기술이 개발자 대신 SQL을 동적으로 만들어서 실행.
  • 각각의 데이터베이스마다 다른 SQL을 사용하는 문제도 해결

SQL Mapper vs ORM 기술

  • SQL Mapper는 SLQ만 작성할 줄 알면 금방 배울 수 있다
  • ORM 기술은 SQL을 작성하지 않아도 돼 개발 생산성이 매우 높아지나, 깊이있는 학습이 필요하다.
  • 이러한 기술들 모두 내부에서는 JDBC를 사용한다

작동 원리

  1. 애플리케이션 로직에서 커넥션이 필요하면 DriverManager.getConnection()을 호출
    • JDBC가 제공하는 DriverManager는 라이브러리에 등록된 DB 드라이버들을 관리하고, 커넥션을 획득하는 기능을 제공
  2. DriverManager는 라이브러리에 등록된 드라이버 목록을 자동으로 인식하고 순차적으로 드라이버들에게 정보를 넘겨 커넥션을 획득할 수 있는지 확인
    • 드라이버는 URL, Username, password 등의 정보를 체크하여 처리 가능한 요청인지 확인하고 아닐 경우 처리할 수 없다는 결과를 반환, 다음 드라이버에 순서가 넘어감.
  3. 해당하는 커넥션 구현체(JDBC java.sql.Connection 인터페이스를 구현)가 클라이언트에 반환

Connection Pool 커넥션 풀

데이터베이스 커넥션 과정

  1. 애플리케이션 로직은 DB 드라이버를 통해 커넥션을 조회
  2. DB 드라이버는 3 way handshake와 같은 네트워크 동작을 통해 DB와 TCP/IP 커넥션 연결
  3. DB 드라이버는 TCP/IP 커넥션 연결에 성공하면 ID, password와 같은 부가 정보를 DB에 전달
  4. DB는 ID와 password를 통해 내부 인증을 완료하고 DB 세션을 생성
  5. DB는 커넥션 생성이 완료되었다는 응답 전달
  6. DB드라이버는 커넥션 객체를 생성하여 애플리케이션에 반환

➡️ 커넥션을 새로 생성하기 위해 리소스를 매번 사용해야 하고 시간이 많이 소요된다. 이러한 불편함을 해결하기 위해 커넥션을 미리 생성해두고 필요할 때 사용하는 Connection Pool이 등장하였다

작동 원리

  • 애플리케이션을 시작하는 시점에 커넥션풀이 필요한 만큼의 커넥션을 미리 확보하여 풀에 보관
    • 적절한 커넥션 풀의 커넥션 수는 서비스의 특징, 애플리케이션 서버 스펙, DB 서버 스펙에 따라 달라지나 보통 기본 값은 10정도
    • DB에 무한정 커넥션이 생성되는 것을 방지하여 DB를 보호하는 효과
  • 커넥션 풀에 보관된 커넥션은 TCP/IP로 DB와 커넥션 연결되어있어 언제든 즉각적으로 DB에 SQL을 전달할 수 있음
    • DB 드라이버를 통해 커넥션을 획득하는 것이 아니라 객체 참조를 통해 이미 생성되어있는 커넥션을 사용해서 SQL을 DB에 전달하고 응답 받음
    • 커넥션을 사용하고 나면 해당 커넥션을 그대로 커넥션 풀에 반환

대표적인 커넥션 풀 오픈소스

commons-dbcp3, tomcat-jdbc pool, HikariCP

DataSource

  • java.sql.DataSource : 커넥션을 획득하는 방법을 추상화하는 인터페이스
    • DriverManager를 통해 커넥션을 획득하다가 HikariCP와 같은 커넥션풀을 사용하도록 변경하거나, 또는 HikariCP를 통해 커넥션을 획득하다가 dbcp2 커넥션풀을 사용하도록 변경하는 경우, 커넥션을 획득하는 애플리케이션 코드도 함꼐 변경해야 했다. 이러한 불편함을 해결하기 위해 커넥션을 획득하는 방법을 추상화
  • 대부분의 커넥션 풀은 DataSource 인터페이스를 이미 구현해두어 애플리케이션 로직은 DataSource 인터페이스에만 의존하여 작성하면 된다
    • DriverManagerDataSource를 사용하지 않아 DataSource 기반의 커넥션 풀로 변경하는 경우 직접 관련 코드를 작성해야 하지만, Spring에서는 DriverManagerDataSource라는 구현체를 제공

설정과 사용의 분리

  • 설정 : DataSource를 생성하고 필요한 속성들을 사용하여 URL, USERNAME, PASSWORD와 같은 정보를 입력하는 것. 설정과 관련된 속성들은 한 곳애 모아두는 것이 유지보수에 용이
  • 사용 : 설정은 신경쓰지 않고 DataSourcegetConnection()만 호출해서 사용