[Java] JDBC

artp·2025년 4월 1일
0

java

목록 보기
27/32
post-thumbnail

1. JDBC란?


자바는 데이터베이스(DB)와 연결하여 데이터를 삽입, 조회, 수정, 삭제(CRUD)할 수 있도록 JDBC(Java Database Connectivity)라는 표준 API를 제공합니다.
이를 통해 데이터베이스 연결, SQL 쿼리 실행, 결과 처리 등의 작업을 수행할 수 있습니다. JDBC는 데이터베이스와의 통신을 추상화하여 DBMS에 종속되지 않고 다양한 DBMS(MySQL, Oracle, PostgreSQL 등)에서 동일한 방식으로 사용할 수 있습니다.

  • 자바는 다양한 데이터베이스와 통신할 수 있도록 JDBC(Java Database Connectivity)라는 표준 API를 정의했습니다.
  • JDBC는 자바에서 DBMS 종류에 상관없이 일관된 방식으로 데이터베이스에 접근할 수 있도록 하기 위한 표준 규칙(인터페이스 모음)입니다.

자바는 JDBC를 java.sqljavax.sql 패키지에 나눠서 제공합니다.

java.sql 패키지

  • 기본 JDBC 인터페이스
  • Connection, Statement, ResultSet 등

javax.sql 패키지

  • 확장 JDBC 인터페이스
  • DataSource, ConnectionPoolDataSource 등

각 DBMS는 이 인터페이스들을 구현한 .jar 파일(JDBC 드라이버)를 제공합니다.

  • MySQL용 드라이버 → MySQL 서버랑 통신하는 로직을 가짐
  • Oracle용 드라이버 → Oracle DB랑 통신하는 로직을 가짐

JDBC 드라이버는 java.sql과 javax.sql에 정의된 인터페이스들을 구현한 클래스 집합으로, 실제로 자바 애플리케이션이 DBMS와 통신할 수 있도록 해주는 역할을 합니다.

  • JDBC 드라이버가 있어야 실제로 자바 코드가 SQL을 실행하고 DB에서 데이터를 주고받을 수 있습니다.
  • JDBC 드라이버는 자바 코드가 실제 DBMS 서버와 TCP 통신을 하고, SQL 문장을 전송하고, 결과를 받아오는 모든 내부 동작을 담당합니다.

2. JDBC 구성 요소

JDBC는 크게 다음 두 가지로 구성됩니다.

  • Java 표준 인터페이스: java.sql, javax.sql 패키지에 정의된 인터페이스 집합
  • JDBC 드라이버: 각 DBMS가 위 인터페이스를 구현하여 제공하는 .jar 파일

2.1 Java 표준 인터페이스

Java는 JDBC를 위해 java.sqljavax.sql 두 패키지를 제공합니다.

  • java.sql 패키지: 기본 JDBC 인터페이스를 담고 있으며, JDBC의 핵심 기능을 담당합니다.
  • javax.sql 패키지: 확장 JDBC 인터페이스를 담고 있으며, 커넥션 풀, 트랜잭션 관리 등 고급 기능을 담당합니다.

각 패키지는 데이터베이스와의 연결, SQL 쿼리 실행, 결과 처리 등을 위한 다양한 인터페이스를 정의합니다.

2.1.1 기본 JDBC 인터페이스 (java.sql 패키지)

java.sql은 JDBC의 기본 기능을 담당하는 핵심 인터페이스들을 포함합니다.

Driver

  • JDBC 드라이버가 구현해야 하는 인터페이스입니다.
  • 자바 프로그램이 사용할 수 있도록 JDBC 드라이버를 등록하고, 연결을 생성하는 기능을 합니다.
  • 보통 Class.forName(...)으로 드라이버 클래스를 로딩하면 자동으로 등록됩니다.

Connection

  • DB와의 연결을 나타내는 인터페이스입니다.
  • Statement, PreparedStatement, CallableStatement 등을 생성할 수 있으며, 트랜잭션을 시작하거나 종료할 수 있습니다.
  • commit(), rollback(), close() 등의 메서드도 포함됩니다.

Statement

  • SQL 문을 실행하는 가장 기본적인 인터페이스입니다.
  • 주로 정적인 SQL 문을 실행할 때 사용됩니다.
  • 예: SELECT * FROM user, DELETE FROM board

PreparedStatement

  • Statement의 확장 인터페이스로, 파라미터가 포함된 SQL 문을 실행할 수 있습니다.
  • SQL 인젝션 방지, 가독성, 성능 측면에서 일반적으로 Statement보다 더 많이 사용됩니다.
  • 예: SELECT * FROM user WHERE id = ?

CallableStatement

  • 데이터베이스에 저장된 프로시저 또는 함수를 호출할 때 사용하는 인터페이스입니다.
  • 예: CALL get_user(?, ?)

ResultSet

  • SQL SELECT 문의 결과를 다룰 수 있는 인터페이스입니다.
  • 행(Row) 단위로 데이터를 읽을 수 있으며, 커서 기반으로 탐색합니다.
  • 예: rs.next(), rs.getString("name"), rs.getInt(1)

2.1.2 확장 JDBC 인터페이스 (javax.sql 패키지)

javax.sql은 JDBC 기능을 확장하기 위한 고급 인터페이스들을 제공합니다.
이 패키지는 주로 커넥션 풀, 트랜잭션 관리, JNDI 연동, 오프라인 데이터 처리 등에 사용됩니다.

DataSource

  • DriverManager를 대체하는 DB 연결 팩토리 인터페이스입니다.
  • 애플리케이션 서버나 프레임워크(Spring, JPA 등)에서 주로 사용됩니다.
  • 커넥션 풀 및 트랜잭션 매니저와 쉽게 통합됩니다.
  • 실무에서는 DriverManager보다 DataSource를 사용하는 방식이 표준입니다.

ConnectionPoolDataSoruce

  • 커넥션 풀 기능을 위한 인터페이스입니다.
  • 하나의 커넥션이 사용 후 반환되어 재사용되도록 설계되어 있어, 고성능 서버 환경에 적합합니다.
  • 실제 풀링 구현체(HikariCP, DBCP 등)는 이 인터페이스를 기반으로 구현됩니다.
  • 개발자가 직접 사용할 일은 거의 없으며, 풀 관리자가 내부에서 사용합니다.

PooledConnection

  • ConnectionPoolDataSource가 생성한 커넥션 객체입니다.
  • 커넥션 풀 내부에서 물리적인 DB 연결을 직접 관리하는 객체이며, 커넥션 풀 관리자에 의해 사용됩니다.
  • 사용자 코드에서는 거의 접근하지 않습니다.

RowSet 계열

  • ResultSet의 확장 개념으로, 더 유연하고 독립적인 데이터 처리 인터페이스입니다.
  • ResultSet과 달리 스스로 DB에 연결할 수 있고, 직렬화/오프라인 처리가 가능합니다.
  • 주요 하위 타입:
    • JdbcRowSet: 연결형 RowSet, ResultSet과 비슷하게 사용 가능
    • CachedRowSet: 비연결형 RowSet, 네트워크 없이 사용 가능 (오프라인 처리)
    • WebRowSet: XML 기반 RowSet, 웹 애플리케이션에 적합

실무에서는 대부분 DataSource만 직접 사용하며, 나머지는 프레임워크나 라이브러리 내부에서 사용됩니다.

2.2 JDBC 드라이버

JDBC 드라이버는 자바 애플리케이션과 특정 DBMS 간의 통신을 담당합니다.
각 DBMS는 java.sqljavax.sql 인터페이스를 구현한 JDBC 드라이버(.jar 파일)를 제공합니다.

개발자는 JDBC 인터페이스만 사용하고, 실제 DB 연결, SQL 전송, 결과 처리 등의 작업은 드라이버가 수행합니다.

2.2.1 드라이버의 역할

  • 자바 표준 JDBC 인터페이스(Connection, Statement, ResultSet 등)의 구현체 역할을 합니다.
  • 자바 코드와 DBMS 간의 SQL 전송, 실행, 결과 수신을 처리합니다.
  • 일반적으로 Class.forName(...)을 통해 명시적으로 로딩하거나, 드라이버가 자동으로 로딩되기도 합니다.
  • JDBC 드라이버가 없으면 자바 프로그램은 데이터베이스와 직접 통신할 수 없습니다.

예시: 각 DBMS별 JDBC 드라이버

DBMSJDBC 드라이버 이름비고
MySQLmysql-connector-jMaven 또는 수동 다운로드 가능
Oracleojdbc8, ojdbc11자바 버전에 따라 드라이버 선택 필요
PostgreSQLpostgresql-<version>.jar오픈소스, PostgreSQL 공식 사이트 제공
MariaDBmariadb-java-clientMySQL 드라이버와 유사, 대체 가능
SQL Servermssql-jdbcMicrosoft 공식 제공
SQLitesqlite-jdbc경량형, 커뮤니티 제공(Xerial 등)

3. JDBC 사용 핵심

JDBC의 핵심 개념은 다음과 같습니다.

개발자는 인터페이스만 사용하고, 각 DBMS가 제공하는 드라이버가 실제 동작을 수행한다.

3.1 개발자는 java.sql (또는 javax.sql) 인터페이스만 사용

개발자는 JDBC를 사용할 때 java.sql 인터페이스만 알면 됩니다.
다음과 같이 코드를 작성하더라도, 실제 동작은 드라이버가 처리합니다.

Connection conn = DriverManager.getConnection(...);
PreparedStatement ps = conn.preparedStatement("SELECT * FROM customer");
ResultSet rs = ps.executeQuery();
  • 위 코드에서 사용하는 Connection, PreparedStatement, ResultSet은 모두 java.sql 인터페이스입니다.
  • 개발자는 이 인터페이스의 사용법만 알면 되고, 해당 인터페이스가 어떤 DBMS에서 어떻게 구현되어 있는지는 몰라도 됩니다.

3.2 구현체는 각 DBMS 드라이버가 제공

예를 들어 MySQL을 사용하는 경우:

Connection conn = DriverManager.getConnection(...);

이 메서드는 내부적으로 MySQL 드라이버(mysql-connector-j.jar)가 등록한 com.mysql.cj.jdbc.Driver 클래스를 통해 동작하며,
반환되는 Connection 객체는 실제로는 com.mysql.cj.jdbc.ConnectionImpl 클래스입니다.

Connection conn = DriverManager.getConnection(...);
// 실제 구현체: com.mysql.cj.jdbc.ConnectionImpl

즉, 개발자는 Connection이라는 인터페이스 타입으로 객체를 다루지만, 실제로는 MySQL 드라이버가 구현한 클래스가 뒤에서 동작하고 있는 것입니다.

3.3 JDBC에서의 다형성

이 구조는 자바의 다형성(polymorphism) 덕분에 가능합니다.

Connection conn = new MysqlConnectionImpl(); // 내부적으로는 이렇게 동작함
  • 개발자는 Connection이라는 상위 타입(인터페이스)만 사용하지만, 실제 객체는 하위 구현체(MysqlConnectionImpl)입니다.
  • 이러한 구조 덕분에 DBMS를 변경할 때도 코드는 그대로 유지한 채, 드라이버만 교체하면 동일한 방식으로 작동합니다.

4. JDBC 사용 흐름

4.1 JDBC 드라이버 로딩

Class.forName("com.mysql.cj.jdbc.Driver");
  • 자바 프로그램이 사용할 JDBC 드라이버 클래스(.jar 파일 내부)를 메모리에 로드합니다.
  • 이 클래스는 내부적으로 java.sql.Driver 인터페이스를 구현하고, 로딩될 때 DriverManager에 자동 등록됩니다.
  • 예외 처리:
    • 클래스를 찾지 못하면 ClassNotFoundException이 발생합니다.
  • 자바 6 이상부터는 생략 가능:
    • 자바 6 이상부터, mysql-connector-j나 ojdbc 등의 드라이버는 자동으로 로딩되도록 되어 있습니다.
    • 하지만 명시적으로 Class.forName(...)을 호출하는 것이 학습이나 디버깅을 위해 권장됩니다.

4.2 데이터베이스 연결 (Connection 객체 생성)

Connection conn = DriverManager.getConnection(
	"jdbc:mysql://localhost:3306:mydb", "user", "password"
);
  • DriverManager는 로딩된 드라이버 중 URL에 맞는 드라이버를 찾아서 연결을 시도합니다.
  • 연결에 성공하면 DB와의 세션(Session)을 나타내는 Connection 객체를 반환합니다.

JDBC URL 구성 예시:

jdbc:mysql://호스트:포트/DB이름?옵션=값
jdbc:oracle:thin:@호스트:포트:SID
  • 예외 처리:
    • 연결 실패 시, SQLException이 발생합니다.

4.3 SQL 실행 객체 생성 (Statement 또는 PreparedStatement)

4.3.1 Statement

Statement stmt = conn.createStatement();
  • 정적 SQL을 실행할 때 사용 (문장이 고정되어 있는 경우)
  • 예: SELECT * FROM customer

4.3.2 PreparedStatement

PreparedStatement ps = conn.prepareStatment(
	"SELECT * FROM customer WHERE id = ?"
);
ps.setInt(1, 101);
  • 동적 SQL (값이 파라미터로 바뀌는 경우)에 적합
  • 보안에 강함 (SQL Injection 방지)
  • 컴파일된 쿼리 재사용 가능 (성능에 유리)

실무에서는 PreparedStatment 사용이 권장됩니다.

4.4 SQL 쿼리 실행

4.4.1 SELECT 문 (조회)

ResultSet rs = ps.executeQuery();
  • 결과는 ResultSet 객체로 반환됩니다.
  • 행(row) 단위로 탐색 가능합니다.

4.4.2 INSERT / UPDATE / DELETE 문 (변경)

int result = ps.executeUpdate();
  • 반영된 행(row)의 수를 반환합니다.

4.5 결과 처리 (ResultSet)

while (rs.next()) {
	String name = rs.getString("name");
    int age = rs.getInt("age");
}
  • rs.next()로 커서를 다음 행으로 이동합니다.
  • rs.getXXX(컬럼명 또는 인덱스)로 각 컬럼 값을 가져옵니다.

주요 메서드 예시

메서드설명
next()다음 행으로 이동 (없으면 false 반환)
getString("컬럼명")문자열 반환
getInt(1)첫 번째 컬럼의 정수값 반환
getDate(...), getDouble(...) 등다양한 타입 지원

4.6 자원 정리 (Close)

rs.close();
ps.close();
conn.close();
  • JDBC의 자원 누수를 방지하기 위해 반드시 명시적으로 close() 호출이 필요합니다.
  • 사용한 순서의 역순으로 닫는 것이 안전합니다.

4.6.1 자바 7 이상부터는 try-with-resources 사용 권장

try (
	Connection conn = DriverManager.getConnection(...);
    PreparedStatement ps = conn.preparedStatement(...);
    ResultSet rs = ps.executeQuery()
) {
	// 실행 및 결과 처리
} catch (SQLException e) {
	e.printStackTrace();
}
  • AutoCloseable 인터페이스 덕분에 자원을 자동으로 닫아줍니다.

5. Driver와 DriverManager

JDBC를 이해할 때 혼동하기 쉬운 두 가지 개념이 있습니다.
바로 Driver 클래스와 DriverManager 클래스입니다.

이 둘은 이름은 비슷하지만, 역할과 사용 위치가 완전히 다릅니다.
JDBC의 전체 구조를 이해하려면 이 둘을 명확하게 구분할 수 있어야 합니다.

5.1 Driver란?

Driver는 JDBC에서 정의한 인터페이스(java.sql.Driver)입니다.
이 인터페이스는 JDBC 드라이버가 반드시 구현해야 하는 규약을 정의합니다.

즉, Driver는 MySQL, Oracle, PostgreSQL 등 DBMS 회사가 구현하는 핵심 인터페이스입니다.

5.1.1 주요 역할

  • JDBC URL을 처리할 수 있는지 확인 (acceptsURL)
  • 실제 데이터베이스 연결을 생성 (connect)
  • 드라이버 버전 및 정보 제공

Driver 클래스를 구현한 클래스를 드라이버의 진입점 클래스(entry-point)라고 합니다.

5.1.2 개발자는 직접 사용할 일이 없음

  • Driver 객체는 개발자가 직접 생성하거나 호출하지 않습니다.
  • 드라이버가 자바에 로딩되면서 자동으로 JDBC 시스템에 등록됩니다.
  • 개발자는 DriverManager만 사용해서 DB에 연결할 뿐입니다.

5.2 DriverManager란?

DriverManager는 자바에서 제공하는 JDBC 연결 관리자 클래스입니다.
개발자가 자바에서 직접 사용하는 클래스는 바로 이 DriverManager입니다.

Connection conn = DriverManager.getConnection(url, user, password);

5.2.1 주요 역할

  • JVM에 등록된 여러 JDBC 드라이버 중에서 알맞은 드라이버를 선택합니다.
  • 해당 드라이버를 통해 DB와의 연결(Connection 객체)을 생성합니다.
  • JDBC 연결 과정을 추상화하여 개발자가 간단한 API로만 사용 가능하게 합니다.

5.3 DriverManager는 Driver를 "선택하고 위임"함

JDBC는 하나의 환경에서 여러 개의 DB 드라이버를 사용할 수 있도록 설계되어 있습니다.
그렇기 때문에 DriverManager는 다음과 같은 방식으로 등록된 드라이버 중 적절한 것을 선택합니다.

5.3.1 흐름 예시

1. 드라이버 클래스 로딩

개발자가 다음 코드를 실행합니다.

Class.forName("com.mysql.cj.jdbc.Driver");

2. 드라이버 등록

MySQL 드라이버 클래스 내부에는 다음 코드가 존재합니다.

static {
	DriverManager.registerDriver(new Driver());
}
  • 이 코드가 실행되면 Driver 구현체가 DriverManager 클래스에 등록됩니다.

3. DB 연결 요청

// Connection conn = DriverManager.getConnection("url", "user", "password");
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/mydb", "root", "pass");

4. DriverManager가 적절한 드라이버 선택

  • 내부적으로 acceptURL(...)을 호출하여 URL을 처리할 수 있는 드라이버를 찾습니다.
  • 적합한 드라이버가 있으면 connect(...)을 호출하여 실제 연결을 생성합니다.

5.3.2 예: MySQL 드라이버 코드 구조

MySQL 드라이버의 진입점 클래스는 다음과 같습니다.

public class Driver extends NonRegisteringDriver implements java.sql.Driver {
    static {
        DriverManager.registerDriver(new Driver());
    }
}
  • 이 클래스는 MySQL 드라이버의 진입점 클래스(entry-point)입니다.
  • 자바에 로딩되면 static 블록을 통해 자동으로 드라이버를 등록합니다.
  • 이후 JDBC URL이 jdbc:mysql://...로 시작하면, 이 드라이버가 선택되어 연결을 수행합니다.

❗️참고
실제 DB 연결 처리, SQL 실행, 결과 조회 등은 내부의 ConnectionImpl, PreparedStatementImpl, ResultSetImpl 같은 클래스들이 수행합니다.
Driver는 진입과 등록만 담당합니다.

5.4 표: Driver vs DriverManager 비교 정리

항목DriverDriverManager
소속java.sql.Driver (인터페이스)java.sql.DriverManager (클래스)
구현 주체각 DBMS 드라이버 제공자자바 표준 라이브러리
개발자 직접 사용❌ (직접 사용하지 않음)✅ (직접 호출)
주요 역할DB 연결 수행 클래스드라이버 선택 및 연결 위임
예시 코드 위치com.mysql.cj.jdbc.DriverDriverManager.getConnection(...)

6. JDBC 흐름 한 눈에 정리

6.1 JDBC 드라이버 로딩

Class.forName("드라이버 클래스 이름");
  • 특정 DBMS(MySQL, Oracle 등)용 JDBC 드라이버 클래스를 JVM에 로딩
  • 클래스 로딩 시, 드라이버의 static 블록이 실행되어 DriverManager에 자동 등록됨

6.2 DB 연결 생성 (Connection 객체 확보)

Connection conn = DriverManager.getConnection(url, user, password);
  • DriverManager가 URL에 맞는 드라이버를 선택해 DB 연결을 생성
  • 이때 필요한 정보:
    • url: DBMS 종류, 호스트, 포트, DB이름
    • user, password: 계정 정보

6.3 SQL 실행 객체 생성

Statement stmt = conn.createStatement();
// 또는
PreparedStatement ps = conn.preparedStatement("SELECT * FROM customer WHERE id = ?");
  • 정적 SQL: Statement
  • 동적 SQL(파라미터 포함): PreparedStatement 사용 권장 (보안, 성능 측면에서 우수)

6.4 SQL 실행 → 결과(ResultSet) 반환

ResultSet rs = stmt.executeQuery(sql); // SELECT
int rows = stmt.executeUpdate(sql); // INSERT, UPDATE, DELETE
  • executeQuery() → 결과 집합(ResuletSet) 반환 (SELECT 용)
  • executeUpdate() → 영향 받은 행의 수 반환 (INSERT, UPDATE, DELETE 용)
  • ResultSet은 테이블 형식의 결과로, 커서는 처음에 첫 행 이전에 위치
    • rs.next()를 호출해야 첫 행으로 이동
    • 컬럼 인덱스는 1부터 시작

6.5 결과 처리

while (rs.next()) {
	// 여러 행인 경우
    System.out.println(rs.getString("name"));
}
if (rs.next()) {
	// 결과가 1행만 있는 경우
    System.out.println(rs.getString("name"));
}

6.6 자원 해제 (close)

rs.close();
stmt.close();
conn.close();
  • 사용한 JDBC 객체는 반드시 close() 해줘야 함
  • 생성한 순서의 역순으로 닫는 것이 원칙 (ResultSet → Statement → Connection)
  • Java 7 이상에서는 try-with-resources 사용 가능

6.7 전체 흐름 요약

Class.forName()DriverManager.getConnection()createStatement() or prepareStatment()executeQuery() or executeUpdate()ResultSet 처리 
→ close()

6.8 표: 암기용 키워드 정리

단계키워드요약
1로딩드라이버 클래스 로딩 및 등록
2연결DB 연결 생성 (Connection)
3준비Statement 또는 PreparedStatement 생성
4실행SQL 실행, 결과 ResultSet 또는 쿼리에 영향받은 행 수 반환
5처리rs.next()로 결과 순회
6정리close()로 자원 해제

6.9 표: JDBC 단계별 클래스와 메서드 정리

단계동작클래스메서드
1드라이버 로딩ClassforName()
2DB 연결DriverManagergetConnection()
3SQL 실행 객체 생성ConnectioncreateStatement() 또는 preparedStatement()
4SQL 실행Statement, PreparedStatementexecuteQuery() 또는 executeUpdate()
5결과 처리ResultSetnext(), getString(), getInt() 등
6자원 해제ResultSet, Statement, Connectionclose()
profile
donggyun_ee

0개의 댓글