✅ 1. JDBC(Java Database Connectivity) 란?
- 자바에서 데이터베이스에 접속하고 SQL을 실행해서 결과를 가져오는 기능을 제공하는 Java API 이다.
- 쉽게말해, 자바 애플리케이션과 데이터베이스 사이의 연결 통로 역할을 해준다고 보면 된다.
- JDBC 는 Java API 로써, JRE에 포함이 되어있으며, 해당 인터페이스 집합들을 데이터베이스(MySQL, Oracle, PostgreSQL 등) 이 해당 자바 인터페이스를 구현해 본인의 데이터베이스에 접근 할 수 있도록 클래스를 만들어 주게 된다. 해당 클래스를 라이브러리로 받아서 이용을 하게 되면, 해당 클래스와 맞는 데이터베이스와 연결을 할 수 있게 된다.
- 참고로 해당 API 는 java.sql 또는 javax.sql 등의 패키지로 제공이 된다.
- 또한, 해당 패키지의 인터페이스를 구현한 클래스를 "JDBC 드라이버" 라고 부른다.
(1) JDBC 구현 및 동작
// 1. 드라이버 로딩 (MySQL인 경우)
Class.forName("com.mysql.cj.jdbc.Driver");
// 2. DB 연결
Connection conn = DriverManager.getConnection(
"jdbc:mysql://localhost:3306/mydb", "username", "password");
// 3. 쿼리 실행
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("SELECT * FROM users");
// 4. 결과 처리
while (rs.next()) {
System.out.println(rs.getString("name"));
}
- 위의 코드와 같이 데이터베이스 사용은 드라이버를 로딩 한 뒤 DB를 연결하여 쿼리를 실행하는 과정을 거친다.
(2) 드라이버 로딩 이유
- Class.forName 을 통해 드라이버를 로딩하게 되면, 정적 블록의 내부 코드가 실행이 된다.
Class.forName("com.mysql.cj.jdbc.Driver");
static {
try {
DriverManager.registerDriver(new Driver());
} catch (SQLException e) {
throw new RuntimeException("Failed to register driver");
}
}
- JDBC 는 인터페이스 기반의 API 이기 때문에, 실제로 동작혀려면 벤더가 제공하는 구현체인 드라이버 클래스가 필요함.
- 해당 드라이버는 우리가 JVM에 로딩시켜줘야 DriverManager 가 이를 인식하고 관리할 수 있음.
- 즉, 드라이버 클래스 로딩은 DriverManager 에 벤더의 드라이버를 등록하기 위함임.
- 쉽게말해, DriverManager 는 커넥션을 만들 수는 있지만, 어떤 드라이버가 들어올지 모르니까 미리 알 수도 없고, 자동으로 로딩을 못함.
- 그래서 직접 Class.forName() 같은 방식으로 드라이버 클래스를 먼저 로딩해서, 그 안에서 DriverManager 에 등록까지 해주게 만들어야 한다는 의미임.
- 하지만, 요즘에는 파일에 자동 로딩 정보를 적어두어 서비스 로더로 불러와서 등록을 해줌.
- 그치만 어차피 내부에선 클래스 로딩해줘야 등록이 된다는 핵심임.
(2) DriverManager
Connection conn = DriverManager.getConnection(
"jdbc:mysql://localhost:3306/testdb",
"user",
"password"
);
- JDBC API 내부에는 인터페이스 뿐 아니라 해당 DriverManager 와 같이 실제 클래스도 포함이 되어있음.
- 해당 DriverManager 는 JDBC 에서 DB 연결을 생성할 때 사용하는 중앙 관리자 클래스임.
- 쉽게 말해, 등록된 드라이버들 중 어떤 걸 써야 할지 골라주고, 연결을 위임해주는 역할을 함.
- java.sql.DriverManager 패키지에 있으며, 정적 클래스임.
[1] DriverManager 내부 동작
- DriverManager.getConnection() 메서드가 호출이 되면, 드라이버 매니저 내부에서 등록된 드라이버 목록을 순회한다.
- 등록된 드라이버 목록은 보통 위의 드라이버 로딩 과정의 static 블록에서 자동으로 등록이 됨.
- 몇개가 있을진 모르겠지만, 각 드라이버에게 URL을 넘겨 acceptsURL(String url) 메서드로 검사를 함.
- 예시로는 "jdbc:mysql://..." url 로 등록이 되어있다면, 해당 MySQL 드라이버가 선택이 됨.
- 선택된 드라이버 구현체의 connect() 메서드 호출
- 이 connect() 메서드 호출 시점에 벤더 구현체가 직접 동작을 하며, 내부의 네트워크 및 다양한 로직이 수행 됨.
- 벤더 내부에선 TCP 소켓 열기, DB 주소 포트로 접속 시도, 로그인 인증, 프로토콜 핸드셰이크, 커넥션 객체 생성 등 작업을 함.
✅ 2. JDBC & DB 통신 원리
(1) JDBC는 네트워크 소켓 기반 통신을 사용함
- JDBC 드라이버는 TCP/IP 기반의 소켓 통신을 이용해 DB와 연결을 함.
- 즉, 결국 JDBC <-> DB 서버는 네트워크 소켓을 통해 데이터를 주고 받는다는 의미임.
- JDBC Driver 즉, 벤더 로직 내부 로직에는 DB 통신 로직이 들어가 있어, 통신이 되며 SQL 을 패킷 형태로 주고 받음
(2) 상세 동작 원리
Java 애플리케이션
↓
[JDBC API 호출]
↓
JDBC Driver (DB 회사가 제공한 구현체)
↓
[TCP/IP 소켓 열기 → DB 서버와 연결 시도]
↓
DB 서버 (예: MySQL, Oracle 등)
↓
[SQL 처리 → 응답 생성]
↑
[응답 결과 소켓으로 전송]
↑
JDBC Driver가 결과를 자바 객체로 변환
↑
Java 애플리케이션에서 ResultSet 등으로 결과 확인
- DriverManager.getConnection() 을 호출하면 connect() 벤더 구현체의 메서드 connect() 메서드가 가 호출이 됨.
- 이후엔, JDBC 드라이버가 내부적으로 Socket 을 열고 데이터베이스 포트에 맞게 패킷을 주고 받으며 통신을 진행함.
- 이후엔, SQL을 실행하면 드라이버가 SQL 문장을 MySQL 프로토콜 형식의 바이너리 패킷으로 바꿔 전송을 함.
- 이후엔, MySQL 서버가 이걸 읽어 SQL 실행 후 결과를 다시 패킷으로 응답을 하게 된다.
(3) 로컬 DB인 경우
- 로컬의 경우에도 Driver 클래스의 connect() 메서드 호출 순간 내부에서 소켓을 만들어서 DB 서버와 TCP 통신을 시작함.
- DB가 같은 컴퓨터인 Localhost 에 있어도, 결국에는 네트워크 스택을 통해서 TCP/IP 통신을 함.
- 하지만 같은 OS 내에서 통신이므로 매우 빠름.
✅ 3. 커넥션 풀 (Connection Pool)
- Connection 객체를 미리 만들어두어 저장하는 풀을 의미하며, 이것은 라이브러리로 제공이 된다.
- 쉽게말해, 해당 라이브러리는 미리 만들어둔 커넥션을 풀에서 가져다가 사용하게 되는 원리이다.
- 즉, DB와 연결된 소켓이 생성되어 있는 상태의 Connection 객체를 미리 풀에 만들어두게 되는 것이다.
- JDBC Driver 는 단순히 Java 코드와 DB를 연결해주는 기능이라 커넥션 풀이 기본적으로 내장이 되어있지 않음.
- 참고: SpringBoot 에는 HikariCP 라는 커넥션 풀 라이브러리가 내장이 되어있음.
(1) 커넥션 풀 동작 원리
- 이 커넥션 풀은 JDBC 드라이버를 감싸서 효율적으로 재사용하도록 만들어진 추가 계층이다.
- JDBC 에서 데이터베이스와 통신하려면 Connection 객체가 필요함
- 이 Connection 객체는 내부적으로 DB 서버와 TCP 소켓을 열고, 로그인(인증) 절차를 거쳐 연결 상태를 유지함.
- Heap 영역에 여러 개의 Connection 객체를 만들어 DB와 연결을 해둠.
(2) 커넥션 풀 사용 이유
- DB 접근 및 SQL 실행을 위한 Connection 객체는 연결 과정에서 TCP 소켓, 로그인 절차를 거치는데 과정이 매우 무겁고 느림
- 이걸 해결하기 위해 커넥션 풀을 활용하여, Connection 객체를 미리 만들어두고 재활용하는 방식을 이용하는 것임.
- 그러면 속도가 증가하며, 리소스 낭비도 적고, 동시 처리 성능도 좋아진다는 장점이 있음.
'공부 > ☕Java' 카테고리의 다른 글
| [Java] 프록시 패턴, 정적 프록시, 동적 프록시: Spring 사례 중심 설명 (1) | 2025.07.09 |
|---|---|
| [Java] 멀티 스레드 프로그래밍 (2) | 2025.06.04 |
| [Java] 자바 스트림(Stream) 개념 + 예제 총정리 📚 (2) | 2025.06.03 |
| [Java] 컬렉션 프레임워크 정리: List, Set, Map 인터페이스와 대표 구현체 총정리 (0) | 2025.05.30 |
| [Java] java.nio 사용법 | Path, Files, FileChannel 예제 모음 (3) | 2025.05.30 |