티스토리 뷰

정리용/DB

[DB 기초] 6-1. JDBC API / Driver

hee-ya07 2025. 3. 19. 14:00

1. JDBC (Java Database Connectivity)

- Java에서 DB와 연결하여 SQL 쿼리를 실행하고 결과를 처리할 수 있도록 도와주는 API

- 구성 요소 :: (1) JDBC API / (2) JDBC Driver

1.1 JDBC API

:: Java 애플리케이션과 DB 간의 상호작용을 위한 인터페이스 집합을 제공하는 API

구성 요소 내용
1.Connection (접속) - DB 연결 관리
- Connection 객체는 DB에 대한 세션을 의미, 쿼리실행, 트랜젝션 관리 등 처리

1) createStatement() :: 쿼리를 실행할 Statement 객체를 생성
2) prepareStatement(String sql) :: 매개변수를 사용하는 쿼리를 실행하는 객체를 생성
3) commit() :: 트랜잭션을 커밋
4) rollback() :: 트랜잭션을 롤백
2. Statement (쿼리) - SQL 쿼리를 DB에 전달하는 객체 / 단순한 SQL 쿼리를 실행 가능

1) executeQuery(String sql) :: SELECT 쿼리 실행 후 결과를 반환
2) executeUpdate(String sql) :: 삽입 / 갱신 / 삭제 등의 쿼리 실행 후, 영향을 받은 행의 개수를 반환
3) execute(String sql) :: SELECT와 INSERT, UPDATE, DELETE 등 다양한 종류의 SQL을 실행
3. PreparedStatement - Statement와 유사 + SQL 쿼리의 성능을 최적화하고 보안을 강화하는 역할
- 매개변수를 사용하여 SQL 쿼리 실행 가능

1) setString(int parameterIndex, String value) :: SQL 쿼리에서 파라미터를 설정
2) executeQuery() :: 매개변수가 포함된 SELECT 쿼리를 실행
4. ResultSet (결과) - 쿼리 실행 후 반환된 데이터를 처리하는 객체
- 테이블 형태의 데이터를 메모리 내에서 순차적으로 처리

1) next() :: 다음 행으로 이동하여 결과를 처리
2) getString(String columnName) :: 컬럼 값을 가져옴 
5. SQLException - JDBC에서 발생하는 예외를 처리하는 클래스

 


1.2 JDBC Driver

:: Java 애플리케이션이 DB와 통신할 수 있도록 지원하는 구현체

:: DB와 연결하고 SQL 명령을 실행하는데 필요한 물리적 연결을 제공 / 브리지 역할

드라이버 유형설명장점단점

드라이버 유형 설명
1. JDBC-ODBC 브리지 드라이버 :: JDBC와 ODBC(구조적 쿼리 언어 호출)를 결합하여,
:: JDBC 애플리케이션이 ODBC DB를 사용할 수 있도록 지원.

장) 쉽게 구성할 수 있으며, 오래된 시스템과 호환됨.
단) 성능이 느리고, 플랫폼 의존적이며, ODBC 드라이버가 필요.
2. 네이티브 API 드라이버 ::JDBC 애플리케이션이 DB에 직접 연결할 수 있도록 네이티브 API를 사용
Ex) MySQL, PostgreSQL

장) 성능이 뛰어나며, DB마다 최적화된 드라이버 제공.
단) 각 DB에 대해 별도의 드라이버가 필요.
3. 네트워크 프로토콜 드라이버 :: JDBC 애플리케이션이 네트워크 프로토콜을 사용하여 DB 서버와 연결
Ex) Oracle Thin Driver

장) 클라이언트와 서버 간의 효율적인 네트워크 연결 제공.
단) 네트워크 지연 및 장애에 취약할 수 있음.
4. 데이터베이스 독립 드라이버 :: JDBC 애플리케이션과 DB 간의 연결을 위해 DB 독립적인 API를 사용

장) DB에 의존하지 않음. 대부분의 DB에서 사용 가능.
단) 설정이 복잡할 수 있으며, 성능은 다른 드라이버들에 비해 떨어질 수 있음.

2. JDBC 연결 흐름

(1) DB 연결 - (2) DB 조작 / 쿼리 실행 - (3) 결과 처리 및 리소스 해제

 

2.1 DB 연결 - JDBC Driver

  • Java에서의 DB 접속은 물리적 접속 or 논리적 접속 중 하나 선택
    - 물리적 접속 :: 매 접속때마다, DB에 직접 붙는것으로 Create/Close 반복
    - 논리적 접속 :: 매 접속때마다, DB에 접속되어있는 Connection Pool 중 하나를 사용 후 반환하여 재사용
종류 내용
1. DriverManager :: 물리적인 연결을 만들고 파기하는 방식
:: DB 연결을 설정할 때마다 직접적으로  새로운 Connection 객체를 create / 쿼리 수행 후 Close
:: 여러 개의 연결을 각각 별도로 관리 - 많은 사용자의 동시처리 문제 발생 
2. DataSource :: 논리적인 연결을 관리 / Connection을 생성하는 역할
:: DB 연결을 미리 풀에 저장 후, DB 연결마다 Connection Pool 내 Connection을 빌려주는 방식
:: 방식은 이미 생성된 연결을 재사용하기 때문에 성능적으로 더 효율적이고, 자원 낭비를 줄임
- 주의 :: DataSource 구현체에 따라 어떤건 자체 Connection Pool 을 갖고, 어떤건 갖고있지 않음
- Spring Boot 2+ 부터 DataSource 표준은 HikariCP(Connection Pool)
- connection를 재사용하기 때문에 최대 커넥션의 수를 제한적으로 설정 가능
- Connection Pool 내 사용가능한 Connection이 없을 경우, 순서대로 대기
- 성능적인 부분을 고려할 때, 최대 커넥션 수는 WAS Thread 수 고려
    => 사용되지 않 DB Connection 은 실질적으로 메모리 공간만 차지하게 되기 때문
더보기

1. DriverManager의 예시

// 1) 접속과 동시에 Connection 을 반환하는 코드
// 각 DBMS 업체마다 DriverManager 에 맞는 Driver 구현하여 제공 (MySQL, PostgresQL 등
Connection connection = DriverManager.getConnection(URL, USER, PASSWORD);

 

// JDBC API 는 3개로 구성되어있다 = Connection 접속 → Statement 쿼리 → ResultSet 결과
// 이 중 Connection 접속 시 DriverManager 사용하면 물리적 접속(Create-Close 반복)

Connection connection = DriverManager.getConnection(url, username, password); // 물리적 연결
Statement statement   = connection.createStatement(); // 객체 
ResultSet resultSet   = statement.executeQuery("SELECT * FROM \"user\" WHERE id = " + userId); //결과

if (resultSet.next()) {
    return new User(
            resultSet.getInt("id"),
            resultSet.getString("name"),
            resultSet.getInt("age"),
            resultSet.getString("job"),
            resultSet.getString("specialty"),
            resultSet.getDate("createdAt")
                    .toInstant()
                    .atZone(ZoneId.systemDefault())
                    .toLocalDateTime()
    );
}

2. DataSource

// 0.1) DataSource 설정
// Spring Boot 2+ 부터 DataSource 표준은 HikariCP(Connection Pool)
HikariConfig config = new HikariConfig();
config.setJdbcUrl(URL);
config.setUsername(USER);
config.setPassword(PASSWORD);
config.setDriverClassName("com.mysql.cj.jdbc.Driver");
config.setMaximumPoolSize(20); // Connection Pool 최대 커넥션 수 설정
config.setMinimumIdle(10); // 사용을 위해 커넥션 풀에 유지해놓을 커넥션 수 (IDLE)

// 0.1) DataSource 생성
HikariDataSource hikariDataSource = new HikariDataSource(config);

// 1) 접속을 Connection Pool 에서 가져오는 코드
Connection connection = hikariDataSource.getConnection();

2.2 DB 조작 : JDBC APIs

:: JDBC는 DB 접속 / 쿼리 / 결과에 대한 명세(API)를 제공.

:: Spring 에서 학습했던 DAO의 개념에 매핑

더보기

2.2-1 DAO(Data Access Object) 패턴

:: DB와의 상호작용을 캡슐화하여 비즈니스 로직과 데이터베이스 구현을 분리하는 설계 패턴

:: DB에 대한 접근을 관리하는 객체인 DAO를 통해 모든 DB의 연산(CRUD) 처리

:: DAO는 JDBC를 사용하여 DB에 접근하고, 비즈니스 로직에 맞는 데이터를 반환 / 저장하는 역할

  • JDBC API 는 3개로 구성되어있다 = Connection 접속 → Statement 쿼리 → ResultSet 결과

1. Connection 인터페이스
:: DB 연결 관리 객체 (앞선 JDBC Driver 통해 취득 - DriverManager / DataSource)
:: 트랜잭션 처리를 위해 Auto-Commit 기능을 제공(기본적으로 true로 설정, 각 SQL 쿼리 실행 후 자동 커밋)

Connection connection = DriverManager.getConnection(dbUrl, dbUser, dbPassword);
connection.setAutoCommit(false); // Auto-Commit 비활성화

// SQL 쿼리 실행 - Auto-Commit 비활성화일 때, 직접 설정 필요

connection.commit(); // 트랜잭션 커밋
connection.rollback(); // 트랜잭션 롤백

2. Statement 인터페이스 

:: DB에 쿼리 전송 및 실행

인터페이스의 종류 내용 
1. Statement: - 기본적인 SQL 쿼리를 실행할 때 사용
- 쿼리문에 파라미터를 동적으로 삽입X - SQL 인젝션 등의 보안 위험
2. PreparedStatement: - 파라미터 바인딩을 사용 / 파라미터가 쿼리의 일부분으로 자동 처리
- 작은 따옴표 및 기타 특수문자를 변환 (Java 이스케이핑)
- string-concatenating 기법인 SQL 인젝션 방어에 유리
- SQL 구문에 대한 실행 계획을 캐싱하여, 동일한 구문이 반복될 때 더 빠르게 실행
3. CallableStatement: - 주로 저장 프로시저를 호출할 때 사용
- 저장 프로시저 :: DB에 저장된 자주 사용하는 쿼리 / 로직의 코드 블록
더보기

예시
1. Statement

Statement stmt = connection.createStatement();
ResultSet rs = stmt.executeQuery("SELECT * FROM users WHERE name = '" + userName + "'");

2. PreparedStatement

// 문제 발생) name 변수에 “' OR 1=1 AND 'a'='a” 입력 시 모든 MEMBER 결과 조회
String name = “' OR 1=1 AND 'a'='a”;
String query = "SELECT * FROM MEMBER WHERE NAME = '" + name + "'";
// 해결)PreparedStatement를 사용하여, 내부적으로 이스케이핑 수행 후 값 주입
String prepareStatement = "SELECT * FROM MEMBER WHERE NAME = ?";
PreparedStatement preparedStatement = connection.prepareStatement(prepareStatement);
preparedStatement.setString(1, loginName);

3. CallableStatement

String sql = "{call getUserById(?)}";
CallableStatement stmt = connection.prepareCall(sql);
stmt.setInt(1, userId);
ResultSet rs = stmt.executeQuery();

3. ResultSet 인터페이스

:: 쿼리 실행 결과를 담고 있는 객체로, DB 쿼리의 결과 데이터를 행(row) 단위로 처리

ResultSet 주요 메서드 내용 
next() - 기본적으로 첫 번째 행 포인트
- 결과셋에서 다음 행으로 이동
getString() / getInt() / getDate() - 결과 행의 특정 컬럼에 접근하여 데이터 read
String sql = "SELECT id, name FROM users";
Statement stmt = connection.createStatement();
ResultSet rs = stmt.executeQuery(sql);

while (rs.next()) {
    int id = rs.getInt("id");
    String name = rs.getString("name");
    System.out.println(id + ": " + name);
}

참조 

ASAC 수업자료

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/04   »
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30
글 보관함