[DB] JDBC란?
서버에서는 데이터를 데이터베이스에 저장하고 있습니다. 그리고 데이터베이스에는 MySQL, Oracle과 같이 다양한 종류가 있죠. 여기서 문제가 발생합니다. 첫째로, 특정 데이터베이스를 사용하다가 다른 종류의 데이터베이스로 변경하면 애플리케이션 서버에 개발된 데이터베이스 사용 코드도 함꼐 변경해야 합니다. 그리고, 개발자가 각각의 데이터베이스마다 커넥션 연결, SQL 전달, 그 결과를 응답받는 방법을 새로 학습해야 됩니다.
위와 같은 문제를 해결하기 위해 JDBC라는 자바 표준이 등장합니다. 위키 백과를 보면 JDBC를 아래와 같이 정의합니다.
JDBC(Java Database Connectivity)는 자바에서 데이터베이스에 접속할 수 있도록 하는 자바 API다. JDBC 는 데이터베이스에서 자료를 쿼리 하거나 업데이트하는 방법을 제공한다.
자바에서 이렇게 표준 인터페이스를 정의해두었기 때문에, 개발자는 이제 이 표준 인터페이스만 사용해서 개발하면 데이터베이스의 종류가 바뀌어도 애플리케이션 코드를 크게 변경하지 않아도 됩니다. 아래에서 JDBC에 대해 더 자세히 알아보겠습니다.
JDBC 표준 인터페이스
JDBC 는 위 그림과 같이 3가지 기능을 표준 인터페이스로 정의해서 제공합니다.
- java.sql.Connection: 커넥션 연결
- java.sql.Statement: SQL을 담은 내용
- java.sql.ResultSet: SQL 요청 응답
이 JDBC 인터페이스를 각각의 DB 벤더(회사)에서 자신의 DB에 맞도록 구현해서 라이브러리로 제공하고 있습니다. 이것을 JDBC 드라이버라고 합니다. 예를 들어서 MySQL DB에 접근할 수 있는 것은 MySQL JDBC 드라이버라 하고, Oracle DB에 접근할 수 있는 것은 Oracle JDBC 드라이버라 합니다.
즉, JDBC의 등장으로 위의 2가지 문제를 해결할 수 있습니다.
- 데이터베이스를 다른 종류의 데이터베이스로 변경하면 애플리케이션 서버의 데이터베이스 사용 코드도 함께 변경해야 하는 문제 ▶ 애플리케이션 로직은 JDBC 표준 인터페이스에만 의존하기 때문에 데이터베이스를 다른 종류의 데이터베이스로 변경하고 싶으면 각 벤더에 맞는 JDBC 구현 라이브러리(JDBC 드라이버)만 변경하면 됩니다. 즉, 애플리케이션 서버의 사용 코드를 그대로 유지할 수 있습니다.
- 개발자가 각각의 데이터베이스마다 커넥션 연결, SQL 전달, 그리고 그 결과를 응답 받는 방법을 새로 학습해야하 는 문제 ▶ 개발자는 JDBC 표준 인터페이스 사용법만 학습하면 됩니다. 이것만 배워두면 다양한 데이터베이스에 모두 동일하게 적용하여 개발할 수 있습니다.
JDBC 한계
참고로, JDBC가 모든 문제를 해결하는 것은 아닙니다. JDBC의 등장으로 많은 것이 편리해졌지만, 각각의 데이터베이스마다 SQL, 데이터 타입 등의 일부 사용법이 다릅니다. 즉, 데이터베이스를 변경하면 JDBC 코드는 변경하지 않아도 되지만, SQL은 해당 데이터베이스에 맞도록 변경해야 합니다. (참고로 JPA(Java Persistence API)를 사용하면 이렇게 각각의 데이터베이스마다 다른 SQL을 정의해야 하는 문제도 많은 부분 해결할 수 있다)
JDBC를 사용하는 방법
JDBC를 직접 사용하는 것보다는 JDBC를 편리하게 사용하는 다양한 기술이 존재하는데, 대표적으로 SQL Mapper와 ORM 기술이 있습니다.
위 그림에서 볼 수 있듯이, SQL Mapper는 개발자가 SQL을 작성하여 Mapper에 전달하고, Mapper가 JDBC에게 전달하는 방식입니다. ORM 기술은 객체를 관계형 데이터베이스 테이블과 매핑해주는 기술입니다. SQL Mapper와 달리 개발자가 반복적인 SQL을 직접 작성하지 않고 ORM 기술이 직접 SQL을 동적으로 생성하여 실행해 줍니다.
SQL Mapper의 대표적인 기술은 스프링 JDBC Template, MyBatis 가 있고, ORM의 대표 기술은 JPA, Hibernate, EclipseLink 등이 있습니다.
JDBC 사용해보기 (H2 Database 사용)
build.gradle
H2 Database 사용을 위한 Dependency를 추가합니다.
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-jdbc'
compileOnly 'org.projectlombok:lombok'
runtimeOnly 'com.h2database:h2'
annotationProcessor 'org.projectlombok:lombok'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
//테스트에서 lombok 사용
testCompileOnly 'org.projectlombok:lombok'
testAnnotationProcessor 'org.projectlombok:lombok'
}
데이터베이스 연결
JDBC 실습 전, 먼저 원하는 데이터베이스 서버를 실행해 두어야 합니다. 여기서는 H2 데이터베이스를 활용합니다.
H2 데이터베이스 설정하는 법은 아래 블로그에 정리가 잘 되어 있어 첨부합니다.
Spring Boot에 H2 Database 설정, H2 Console 띄우기 (tistory.com)
기본 설정 구현하기
데이터베이스에 접속하는데 필요한 기본 정보를 편리하게 사용할 수 있도록 상수로 정의합니다.
public abstract class ConnectionConst {
public static final String URL = "jdbc:h2:tcp://localhost/~/test";
public static final String USERNAME = "sa";
public static final String PASSWORD = "";
}
DBConnectionUtil.class
이 클래스에서 데이터베이스와 연결합니다. 이를 위해 JDBC가 제공하는 `DriverManager.getConnection(..)` 을 사용합니다. 이렇게 하면, 라이브러리에 있는 데이터베이스 드라이버를 찾아서 해당 드라이버가 제공하는 커넥션을 반환해줍니다. (여기서는 H2 데이터베이스 드라이버가 작동해 실제 데이터베이스와 커넥션을 맺고 결과를 반환해 줍니다.)
package hello.jdbc.connection;
import lombok.extern.slf4j.Slf4j;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import static hello.jdbc.connection.ConnectionConst.*;
@Slf4j
public class DBConnectionUtil {
public static Connection getConnection() {
try {
Connection connection = DriverManager.getConnection(URL, USERNAME, PASSWORD);
log.info("get connection={}, class={}", connection, connection.getClass());
return connection;
} catch (SQLException e) {
throw new IllegalStateException(e);
}
}
}
DBConnection test
DBConneciton이 잘 맺어졌는지 test 하는 파일입니다. 실행해 보면 ` class=class org.h2.jdbc.JdbcConnection` 부분을 확인할 수 있는데 이것이 바로 H2 데이터베이스 드라이버가 제공하는 H2 전용 커넥션입니다. (H2 데이터베이스는 서버에 띄어져 있어야 합니다!)
package hello.jdbc.connection;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
import java.sql.Connection;
import static org.assertj.core.api.Assertions.assertThat;
@Slf4j
class DBConnectionUtilTest {
@Test
void connection() {
Connection connection = DBConnectionUtil.getConnection();
assertThat(connection).isNotNull();
}
}
실행 결과 H2 데이터베이스 드라이버가 제공하는 H2 전용 커넥션을 반환하는 것을 확인할 수 있습니다.
12:43:32.656 [Test worker] INFO hello.jdbc.connection.DBConnectionUtil - get connection=conn0: url=jdbc:h2:tcp://localhost/~/test user=SA, class=class org.h2.jdbc.JdbcConnection BUILD SUCCESSFUL in 25s
JDBC 동작 방식
- 애플리케이션 로직에서 DriverManager.getConnection() 호출로 Connection 요청
- DriverManager는 라이브러리에 등록된 드라이버 목록을 인식하여 이 드라이버들에게 순서대로 아래 정보를 넘겨서 커넥션을 획득할 수 있는지 확인
- URL: 예) jdbc:h2:tcp://localhost/~/test
- 이름, 비밀번호 등 접속에 필요한 추가 정보
- 여기서 각각의 드라이버는 URL 정보를 체크해서 본인이 처리할 수 있는 요청인지 확인합니다. 예를 들어서 URL이 jdbc:h2 로 시작하면 이것은 h2 데이터베이스에 접근하기 위한 규칙입니다. 따라서 H2 드라이버는 본인이 처리할 수 있으므로 실제 데이터베이스에 연결해서 커넥션을 획득하고 이 커넥션을 클라이언트에 반환합니다. 반면에 URL이 jdbc:h2 로 시작했는데 MySQL 드라이버가 먼저 실행되면 이 경우 본인이 처리할 수 없다는 결과를 반환하게 되고, 다음 드라이버에게 순서가 넘어갑니다.
- 이렇게 찾은 커넥션 구현체가 클라이언트에 반환
이렇게 DB와 연결한 JDBC 를 사용하여 DB에 데이터를 저장, 조회, 수정, 삭제 해보도록 하는 코드는 아래 포스팅에 정리하였습니다.