Java

JDBC란?

H-jinny 2024. 9. 9. 11:30

DBMS에는 다양한 종류가 있다. 그리고 다양한 언어로 DBMS들에 접근하려면 각각에 맞는 언어가 필요하다. 자바에서는 DB에 접근하기 위한 표준화된 API로 JDBC를 이용할 수 있다. JDK 1.1 버전에 출시된 오랜 기술로써 SQL Mapper나 ORM의 기반이 되었다. 그래서 이번에는 이 기반이 되는 JDBC에 대해 정리하려고 한다.

 

 

 

JDBC

JDBC(Java Database Connectivity)는 Java를 사용해 데이터베이스에 접근할 수 있도록 하는 자바 API 이다. 이를 통해 DB에 접속, SQL 실행하여 데이터를 다루는 작업을 할 수 있다.

 

 

JDBC 구조

자바 응용프로그램에서는 JDBC 드라이버 매니저를 통해 JDBC 드라이버를 로드하여 사용하므로, DBMS가 바뀌어도 공통으로 사용할 수 있다. 그림으로 보면 다음과 같다.

참고 자료 기반 JDBC 구조

 


JDBC 드라이버 매니저

  자바 API에서 지원하는 클래스로, JDBC 드라이버 로드 및 관리

JDBC 드라이버

  JDBC 드라이버의 구현체를 통해 특정 데이터베이스 벤더에 대한 연결과 데이터베이스 작업 처리

 

데이터베이스 벤더(DB vender)

DBMS를 개발하고 판매하는 기업. Oracle, MySQL, PostgreSQL 등이 있다.

 

 

 

위의 구조를 기반으로 JDBC는 다음 흐름처럼 동작한다.

 

0. JDBC API 사용을 위해 JDBC 드라이버 로딩 후 데이터베이스와 연결

1. JDBC 드라이버 매니저를 통해 Connection 획득

2. Connection을 통해 Statement 생성

3. 질의 수행 및 Statement를 통해 ResultSet 생성

4. ResultSet을 통해데이터 획득 

5. 리소스 정리

 

 

MySQL로 실제로 사용하는 예제 코드이다.  

import java.sql.*;

publicclass Jdbc_Ex {
  public static void main(String[] args) {
  	String url = "jdbc:mysql://localhost:3306/databaseName";
    String username = "myUsername";
    String password = "myPassword";
    
    Connection conn;
    Statement stmt = null;
    ResultSet srs = null;
    
    try {
      // (0) JDBC 드라이버 로드
      Class.forName("com.mysql.jdbc.Driver");
    
      // (1) DriverManager를 통해 Connection 획득)
      conn = DriverManager.getConnection(url, username, password);
      
      // (2) Connection을 통해 Statement 생성
      stmt = conn.createStatement();
      
      // (3) 질의 수행 및 Statement를 통해 ResultSet 생성
      String sql = "SELECT * FROM users";
      srs = stmt.excuteQuery(sql);
      
      // (4) ResultSet을 통해 데이터 획득
      while (srs.next()) {
        int id = srs.getInt("id");
        String name = srs.getString("name");
        int age = srs.getInt("age");
      }
      
      // (3b) 레코드 추가 
      stmt.excuteUpdate("insert into users (name, id, age) values('홍길동', '0123', '20');");
      
      // 데이터 수정
      stmt.excuteUpdate("update users set id='1234' where name='홍길동'");
      
      // 레코드 삭제
      stmt.excuteUpdate("delete from users where name='홍길동'");
    } catch (ClassNotFoundException e) {
      e.printStackTrace();
    } catch (SQLException e) {
      e.printStackTrace();
    } finally {
      // (5) 리소스 정리
      try {
        if (srs != null) {
          srs.close();
        }
        if (stmt != null) {
          stmt.close();
        }
        if (conn != null) {
          conn.close();
        }
      } catch (SQLException e) {
        e.printStackTrace();
      }
    }
  }
}

 

 

세부 설명을 덧붙이면,

 

(0) MySQL JDBC 드라이버인 com.mysql.Driver 클래스를 로드하여 드라이버 인스턴스 생성 후 DriverManager에 등록. JDBC 4.0 버전이후부터는 드라이버 자동 로딩이 도입되어 생략이 가능

(1) DriverManager는 JDBC 드라이버 매니저 역할로, 자바 응용프로그램을 JDBC 드라이버에 연결시켜주는 클래스. getConnection() 메서드를 통해 데이터베이스에 연결하고 Connection 객체 반환

(2) SQL문 처리용 Statement 객체 생성

(3) Statement 클래스를 이용하여 자바에서 SQL문 실행

(4) SQL문 실행 결과를 받기 위해 ResultSet 클래스 사용

(5) 사용한 자원 정리

 

 

또한 주요 메서드를 살펴보면 다음과 같다.

 

Statement 클래스 주요 메서드

ResultSet executeQuery(String sql) 주어진 sql문 실행 후 결과를 ResultSet 객체에 반환
int executeUpdate(String sql) INSERT, UPDATE, DELETE 같은 sql문 실행 후 영향받은 행의 개수나 0 반환
void close() Statement 객체의데이터베이스와 JDBC 리소스 즉시 반환 

 

데이터 검색은 executeQuery(), 데이터 변경은 executeUpdate()를이용한다.

ResultSet 객체는 현재 데이터의 행(레코드 위치)를 가리키는 커서(cursor)를 관리한다. 초기 값은 첫 번째 행 이전을 가리킨다. 따라서 ResultSet 클래스는 커서 위치와 관련되거나 레코드를 가져오는 메서드를 제공한다.

 

ResultSet 클래스 주요 메서드

boolean first() 커서를 첫 번째행으로 이동 
boolean last() 커서를 마지막 행으로 이동
boolean next() 커서를 다음 행으로 이동
boolean pervious() 커서를 이전 행으로 이동
boolean absolute(int now) 커서를 지정된 행 row로 이동
boolean isFirst() 첫 번째 행이면 true 반환
boolean isLast() 마지막 행이면 true 반환
void close() ResultSet 객체의 데이터베이스와 JDBC 리소스 즉시 반환
Xxx getXxx(String columnLable) 현재 행에서 지정된 열 이름(columnLable)에 해당하는 데이터 반환
Xxx getXxx(int columnIndex) 현재 행에서 지정된 열 인덱스(columnIndex)에 해당하는 데이터 반환

  이 때 Xxx는 해당 데이터 타입을 의미한다.(예 : int형 데이터를 읽는 메서드라면 getInt() )

 

 

 

Connection Pool(커넥션 풀)

DataSource

DataSource란 JDBC명세의 일부분으로 일반화된 연결 팩토리이다. DB와 관련된 Connection 정보를 담고 있으며, bean으로 등록하여 인자로 넘겨준다.

 

그렇다면 계속 언급되는 Connection은 어떤 과정으로 생성되는 것일까?

 

Connection 객체를 생성하는 과정은 다음과 같다.

 

1. 애플리케이션에서 드라이버를 통해 Connection 조회

2. 드라이버가 DB와 TCP/IP Connection 연결

3. TCP/IP Connection이 연결되면 아이디와 패스워드, 부가 정보를 DB에 전달

4. DB는 내부 인증을 거친 후 내부 DB 생성

5. DB의 Connection 생성 완료 응답

6. 드라이버는 Connection 객체를 생성하여 클라이언트에 반환

 

이러한 과정 때문에 Connection을 새로 만드는 것은 비용도 많이 들며 비효율적이다.

그래서 애플리케이션 로딩 시점에 Connection 객체를 미리 생성하고, 데이터베이스에 연결이 필요한 경우 미리 생성한 Connection 객체를 사용하는 방법이 등장했다.

 

즉, Connection Pool이란

Connection 객체를 미리 생성하여 보관, 애플리케이션이 필요할 때 꺼내서 사용할 수 있도록 관리해 주는 것이다.

 

따라서 드라이버를 통해 Connection을 조회, 연결, 인증 등의 과정을 생략하고 필요할 때 참조하고 반납한다.

참고로 스프링 부트 2.0 이후부터는 기본 DBCP로 HikariCP를 사용한다.

 

HikariCP

JDBC Connection Pool Framework. 미리 정해놓은 크기만큼의 Connection을 Connection Pool에 담아놓고, 요청이 들어오면 Thread가 Connection 요청, 담아놓은 Connection 연결해줌

 

Connection을 직접 생성하든 Connection Pool을 통해 획득하든, DataSource 인터페이스를통해 Connection을 획득하는 방법을 추상화하여 일관된 방식으로 데이터베이스와 통신할 수 있다. 그래서 전자의 방식에서 후자의 방식으로 전환하고 싶다면 DataSource 구현체를 JDBC DriverManager 기반의 DriverManagerDataSource에서 HikariCp Connection Pool 기반의 HikariDataSource로 바꿔주면 된다.

 

 

 

참고

황기태, 김효수. (2021). 명품 자바 프로그래밍. 생능출판

https://tecoble.techcourse.co.kr/post/2023-06-28-JDBC-DataSource/

https://ittrue.tistory.com/250

https://gmlwjd9405.github.io/2018/05/15/setting-for-db-programming.html#google_vignette

 

 

 

오타, 지적 감사합니다 :)