장미정원
✨ JDBC와 DataSource 본문
JDBC - Java Database Connectivity
JDBC는 자바에서 데이터베이스에 접속할 수 있도록 하는 API입니다. JDBC는 데이터베이스에서 데이터를 쿼리하거나 업데이트하는 방법들을 추상화하여 인터페이스로 제공합니다.
애플리케이션을 개발할 때 데이터들은 대부분 데이터베이스에 저장하여 사용합니다. 이런 애플리케이션은 데이터베이스에 접근하여 데이터를 가져오거나 업데이트 하는 작업을 필요로 합니다.
애플리케이션에서 데이터베이스에 접근하여 데이터를 다루는 과정은 크게 3가지 단계로 나눌 수 있습니다.
- 커넥션 연결: TCP/IP 커넥션을 통해 데이터베이스에 대한 커넥션을 얻습니다.
- SQL 질의: 연결된 커넥션을 통해 DB에 SQL을 전달합니다.
- 결과 응답: 전달된 SQL을 실행하고 그 결과를 반환합니다.
하지만 각각의 데이터베이스 마다 커넥션 연결, SQL 질의, 결과를 응답하는 방법이 모두 다릅니다.
데이터베이스 종류를 변경한다면 애플리케이션 코드를 변경해야하고 각각의 데이터베이스에 해당하는 커넥션 연결, SQL 질의, 결과 응답에 대한 학습이 필요로 합니다.
이러한 문제점을 해결하기 위해 JDBC라는 자바 표준 API가 등장하게 되었습니다.
JDBC 표준 인터페이스
JDBC는 위에서 살펴본 세가지 기능을 표준 인터페이스로 정의하여 제공합니다.
- java.sql.Connection - 커넥션 연결
- java.sql.Statement - SQL 질의
- java.sql.ResultSet - 질의 결과 응답
이제 개발자는 JDBC의 표준 인터페이스를 사용하여 개발을 하면 됩니다. 이 JDBC 인터페이스를 각각의 데이터베이스 벤더에서 데이터베이스에 맞도록 JDBC 인터페이스를 구현하여 라이브러리로 제공합니다! (이것을 JDBC Driver라고 합니다.)
JDBC를 활용하여 데이터베이스를 변경하여도 애플리케이션 코드는 JDBC 인터페이스를 의존하기 때문에 변경하고자 하는 데이터베이스의 드라이버를 변경하기만 하면 됩니다!
데이터베이스 연결
실제 애플리케이션에서 JDBC를 사용하는 예시를 보여드리겠습니다.
JDBC가 제공하는 DriverManager의 getConnection 메서드를 사용하여 직접 데이터베이스의 커넥션을 얻어올 수 있습니다.
그럼 만약에 여러 종류의 데이터베이스가 라이브러리에 등록되어 있다면 어떻게 올바른 데이터베이스에 대한 커넥션 정보를 얻어오는걸까요?
JDBC가 제공하는 DriverManager는 라이브러리에 등록되어있는 드라이버 목록을 확인합니다.
이 드라이버를 순서대로 순회하면서 커넥션 요청의 정보인 URL 정보를 바탕으로 커넥션을 얻을 수 있는 드라이버인지 확인합니다. 예를 들어 현재 URL이 jdbc:h2 로 시작하기 때문에 h2 데이터베이스 드라이버가 커넥션을 연결하여 클라이언트에 커넥션을 반환합니다!
이렇게 된다면 다른 종류의 데이터베이스를 사용해도 DriverManager의 getConnection 메서드를 사용한다면 비즈니스 로직의 코드는 건들이지 않고 데이터베이스만 변경할 수 있습니다!
JDBC로 데이터 다루기
데이터 저장
이렇게 획득한 Connection으로 데이터를 다루는 방법에 대해 설명하도록 하겠습니다.
해당 로직은 Member 객체를 파라미터로 받아 해당 객체의 내용을 바탕으로 데이터베이스에 저장하는 코드입니다.
먼저 획득한 Connection으로 데이터베이스에 전달할 SQL을 주입하여 Statement를 생성합니다.
미리 작성된 SQL String 데이터에 파라미터로 넣을 값은 "?"로 작성합니다. 생성한 Statement의 메서드를 활용하여 파라미터에 값을 넣을 수 있습니다.
SQL 쿼리가 준비가 완료 되었다면 insert 쿼리를 해야하기 때문에 executeUpdate 메서드를 실행하여 데이터베이스에 실제로 쿼리를 합니다.
쿼리를 실행하고 나면 꼭 리소스를 정리해야합니다! 해당 로직에서는 Connection, Statement를 사용했습니다. 리소스 정리는 항상 역순으로 이루어져야 합니다. (Connection 획득 후 Statement를 만들었기 때문에 역순으로 Statement 종료 -> Connection 종료)
데이터 조회
해당 코드는 파라미터로 Member의 Id를 받아 Member를 조회하는 로직입니다.
먼저 위와 동일하게 Connection과 Statement를 생성합니다. Statement에 주입한 SQL의 파라미터 값인 Member의 Id를 넣어줍니다.
이번에는 데이터를 조회해야하기 때문에 executeQuery 메서드를 실행하여 select 쿼리를 실행합니다.
여기서 반환된 값을 받아야하기 때문에 미리 생성해둔 ResultSet으로 SQL 쿼리의 반환값을 받습니다.
반환 값의 여부를 확인한 후 ResultSet의 메서드를 사용해서 받아오려는 값에 대해 컬럼이름을 키 값처럼 사용해서 반환 값을 꺼내옵니다.
커넥션 풀
데이터베이스 커넥션을 얻기 위해서 일어나는 일련의 과정은 꽤 복잡합니다.
- 애플리케이션에서 커넥션을 요청합니다.
- 드라이버는 데이터베이스와 TCP/IP 커넥션을 연결합니다. (3-way-handshake)
- 드라이버는 연결된 커넥션으로 ID, PASSWORD와 같은 정보를 데이터베이스에 전달합니다.
- 데이터베이스는 인증을 완료한 후 내부에서 세션을 생성합니다.
- 커넥션을 생성하여 클라이언트에 반환합니다.
이렇게 커넥션을 얻는 과정은 시간이 많이 걸리고 복잡한 작업입니다. 이러한 커넥션을 얻는 동작이 반복되어 일어난다면 응답 속도에 좋지 않은 영향을 미치게 됩니다. 이러한 문제를 해결하기 위해 등장한 것이 커넥션 풀 입니다!
커넥션 풀은 이름 그대로 커넥션을 풀에 미리 생성해두고 필요할 때마다 커넥션을 꺼내서 사용하고 다시 풀에 반납하는 방법입니다.
애플리케이션 시작 시점에 커넥션 풀에 커넥션을 일정량 확보하여 풀에 보관합니다. 이렇게 보관된 커넥션들은 데이터베이스와 TCP/IP로 연결되어 있는 상태이기 때문에 필요할 때 즉시 SQL을 데이터베이스에 전달할 수 있습니다.
애플리케이션에서는 비즈니스 로직을 실행할 때마다 새로운 커넥션을 얻는 것이 아니고 이미 생성되어 있는 커넥션을 가져다 사용하기만 하면 됩니다. 비즈니스 로직이 종료된 후 다 사용한 커넥션은 풀에 다시 반환하게 됩니다.
커넥션 풀은 서버당 최대 커넥션 수를 제한할 수 있어 데이터베이스에 무한정 커넥션이 생성되는 것을 막아 데이터베이스를 보호할 수도 있고 여러가지 이점이 매우 많기 때문에 실무에서는 기본으로 사용하는 기술 입니다.
대표적인 커넥션 풀 오픈소스는 hikariCP, DBCP2 등이 있습니다. 그 중 hikariCP는 성능과 안정성이 검증되어 스프링 부트에서도 기본 커넥션 풀로 사용하고 있습니다.
DataSource
DataSource는 커넥션을 획득하는 방법을 추상화한 인터페이스입니다.
데이터베이스의 커넥션을 얻는 방법은 위에서 DriverManager를 사용하거나 Connection Pool을 사용하거나 다양한 방법이 존재합니다.
만약 DriverManager를 사용하여 직접 커넥션을 얻다가 HikariCP를 사용하여 커넥션 풀 방식으로 교체하고 싶다면?
애플리케이션은 DriverManager를 의존하여 개발되어 있었는데 커넥션 풀을 사용한다면 애플리케이션 코드를 변경해야한다..
자바에서는 이런 문제를 해결하기 위해 DataSource라는 인터페이스를 제공하여 데이터베이스 커넥션을 얻는 방법을 추상화한 인터페이스를 제공합니다!
DataSource 인터페이스의 getConnection이라는 메서드를 DriverManager나 여러 커넥션 풀 기술들이 구현해 두어서 애플리케이션은 구체 기술에 의존하지 않고 DataSource 인터페이스를 의존하여 개발할 수 있다. 만약 커넥션 구현 기술을 변경하고 싶으면 해당 구현체로 갈아 끼우기만 하면 애플리케이션 코드를 변경하지 않고도 기술을 변경할 수 있다.
추가로 DriverManager를 사용하여 개발할 때는 커넥션을 획득할 때마다 파라미터로 URL, USERNAME, PASSWORD 값을 넘겨주었지만 DataSource를 사용하면 DataSource가 만들어지는 시점에 미리 설정 정보를 넣어두고 사용할 때는 간단하게 메서드만 호출하면 되기 때문에 URL, USERNAME, PASSWORD 같은 값들에 의존하지 않을 수 있다! 덕분에 객체를 생성하는 부분과 사용하는 부분을 명확하게 분리할 수 있다.
마무리
데이터베이스의 접근 기술인 JDBC와 커넥션 풀, DataSource에 대해 설명하는 글을 작성하였습니다. 최신 데이터 접근 기술인 JPA 기술도 결국 low-level에서는 JDBC기술을 사용하여 구현되어 있습니다. JPA가 복잡한 부분은 추상화 해주어 간단하게 데이터베이스 관련 작업을 할 수 있지만 내부 로직을 이해하고 사용해야 나중에 문제가 발생해도 넓은 시각으로 바라볼 수 있다고 생각합니다!
이번 내용에 대해 공부하면서 과거 개발자 분들의 현대 개발자들이 오로지 개발에만 집중할 수 있게 힘써주신 노력을 느낄 수 있어서 좋았습니다!
참고자료
https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-db-1
'Back-end' 카테고리의 다른 글
✨ GC 이해하기 (0) | 2024.08.02 |
---|---|
✨ 스프링을 사용하는 이유 (0) | 2024.07.29 |
교내 프로젝트 운영중 발생한 동시성 문제와 IntegerOverFlow 문제 해결기 (0) | 2024.06.16 |
교내 프로젝트 느려터진 조회성능 향상기 (preflight, N+1, QueryDSL) (0) | 2024.06.04 |
✨ JVM 가상머신 (0) | 2024.05.28 |