본문 바로가기

카테고리 없음

📌 TIL - 데이터베이스 연결 (Driver)

🔹 1. 데이터베이스 드라이버의 역할과 종류

✅ 드라이버란?

  • 애플리케이션과 DB 사이의 중개자 역할을 함.
  • 애플리케이션의 JDBC 요청을 DB가 이해할 수 있는 형태로 변환하고, 응답도 다시 자바 객체로 역변환.

✅ 드라이버의 종류

데이터베이스드라이버 클래스명
MySQL com.mysql.cj.jdbc.Driver
PostgreSQL org.postgresql.Driver
H2 org.h2.Driver
Oracle oracle.jdbc.OracleDriver
 

💡 팁: DBMS마다 드라이버가 다르므로 사용 중인 DB에 맞게 드라이버를 지정해야 함.

 

🔹 2. JDBC란 무엇인가?

✅ JDBC (Java Database Connectivity)

  • 자바 애플리케이션에서 DB와 연결하고 SQL을 실행하기 위한 표준 API입니다.
  • JDBC는 단순히 인터페이스 집합이며, 실제 동작은 DBMS에 맞는 드라이버 구현체가 수행합니다.

✅ JDBC 드라이버 종류 (Type 1~4)

타입설명특징
Type 1 JDBC-ODBC 브리지 구식, 거의 사용하지 않음
Type 2 네이티브 API 기반 드라이버 OS 의존적
Type 3 네트워크 프로토콜 드라이버 중간 서버 필요
✅ Type 4 순수 Java 드라이버 가장 널리 사용됨, OS 독립적

 

🔹 3. Spring Boot의 JDBC 구성

Spring Boot는 JDBC를 사용하는 데 필요한 거의 모든 것을 자동으로 설정해 주는 프레임워크입니다. spring-boot-starter-jdbc를 통해 아래와 같은 기능을 제공합니다

 

✅ 포함된 핵심 기능

구성 요소설명
JdbcTemplate JDBC 작업을 간편하게 처리하도록 도와주는 클래스 (SQL 실행, 결과 조회 등)
DataSource 커넥션 풀 또는 단일 커넥션 생성 등 DB 연결에 필요한 자원 관리
자동 구성 application.yml 설정을 바탕으로 자동으로 JDBC 환경을 설정

✅ 의존성 추가(주석을 읽어보기!!!!!)

dependencies {
    // 애플리케이션이 종료되지 않고 웹 서버를 띄울 수 있도록 도와줍니다. (H2 Console 웹페이지 띄우기)
    implementation 'org.springframework.boot:spring-boot-starter-web'

    // 스프링 부트 애플리케이션에서 JDBC를 사용하기 위한 모든 필수 의존성을 포함하고 있습니다.
    // JDBC API를 통해 데이터베이스와의 연결 및 SQL 쿼리 실행을 쉽게 할 수 있도록 도와줍니다.
    implementation 'org.springframework.boot:spring-boot-starter-jdbc'

    // H2는 자바 기반의 인메모리 데이터베이스로,
    // 로컬 개발 및 테스트 환경에서 DB 서버를 별도로 구축하지 않고 사용할 수 있게 해 줍니다.
    // 빠르고 경량이며 설정이 간단하다는 장점이 있습니다.
    runtimeOnly 'com.h2database:h2'
}

 

✅ 포함 요소 상세

구성 요소설명
JdbcTemplate Spring에서 제공하는 JDBC 간편 도구. 반복되는 Connection, Statement, ResultSet 처리를 자동화. SQL 실행, 조회, 업데이트, 트랜잭션 처리 등에서 매우 유용함.
DataSource 커넥션 풀을 관리하거나 DB 연결 정보를 담는 인터페이스. 내부적으로 커넥션 풀 라이브러리(HikariCP 등)를 통해 실제 커넥션을 관리.
DriverManagerDataSource 가장 기본적인 DataSource 구현체. 커넥션 풀 없이 매번 새로운 연결을 생성. 학습/테스트 용도로만 권장. 실무에서는 HikariDataSource가 기본.
자동 구성 spring.datasource.*로 시작하는 설정 값을 기반으로 Spring Boot가 DataSource, JdbcTemplate, 트랜잭션 매니저 등을 자동 생성해줌.

✅ Spring Boot JDBC 사용의 장점

1. 자동 구성 기반으로 빠른 개발

  • spring-boot-starter-jdbc를 추가하고 application.yml만 작성하면 DB 연결 설정이 완료됩니다.
  • 수동으로 드라이버 등록, 커넥션 열기, 닫기 등은 필요 없습니다.

2. 예외 처리 일원화

  • JDBC는 SQLException을 직접 처리해야 하지만, Spring은 이를 DataAccessException 계열로 포장해줍니다.
  • 예외가 트랜잭션 롤백과 연계되거나, 특정 에러 타입을 쉽게 분기 처리할 수 있음.

3. 코드 간소화 및 가독성 향상

  • JdbcTemplate을 사용하면 다음과 같은 중복 코드 제거 가능:
// 기존 JDBC
Connection conn = ...;
PreparedStatement ps = conn.prepareStatement(sql);
ResultSet rs = ps.executeQuery();

// JdbcTemplate 방식
String sql = "SELECT * FROM users";
List<User> users = jdbcTemplate.query(sql, new UserRowMapper());

4. 트랜잭션 처리 연동

  • Spring Boot는 AOP 기반으로 선언적 트랜잭션 관리가 가능하여, @Transactional 애노테이션만으로도 안전하게 트랜잭션 처리가 가능함.

✨ 팁 요약

팁 1: 실무에서는 DriverManagerDataSource 대신 HikariCP가 기본 제공되며 성능이 훨씬 뛰어납니다.

팁 2: JdbcTemplate은 SQL 실행의 가장 가벼운 방식이며, 성능 및 제어 측면에서 JPA보다 유리한 경우가 있습니다.

팁 3: Spring Boot의 자동 구성은 DataSource, JdbcTemplate, TransactionManager까지 모두 처리해주므로 진입장벽이 매우 낮고 생산성이 높습니다.

🔄 JDBC 실습 흐름

✅ JDBC 작동 순서 & 설명

  1. 드라이버 로드 (자동)
    • 최신 JDBC 드라이버는 JAR만 등록되어 있으면 Class.forName() 없이 자동 로딩됩니다.
  2. Connection 객체 획득
    • DriverManager를 통해 DB와 연결을 맺는 객체 생성.
    • 이 연결을 통해 SQL을 실행할 수 있는 준비 상태를 갖춤.
  3. SQL 실행 객체 생성
    • Statement 또는 PreparedStatement를 통해 SQL 실행 객체 생성.
    • Statement는 SQL을 문자열로 직접 작성.
    • PreparedStatement는 바인딩 방식으로 작성, 보안과 성능에 유리.
  4. SQL 실행 & 결과 처리
    • SELECT 쿼리는 executeQuery()로, 결과는 ResultSet에 저장.
    • INSERT, UPDATE, DELETE는 executeUpdate()로 실행.
    • ResultSet에서 데이터를 꺼낼 때는 next()로 한 행씩 접근 가능.
    • 모든 JDBC 객체는 외부 리소스이므로 반드시 닫아야 함.
    • Java 7부터는 try-with-resources를 사용하면 자동으로 close() 처리됨.
    • 닫아야 할 리소스:
      • ResultSet
      • Statement / PreparedStatement
      • Connection리소스 정리 (try-with-resources)

 JDBC 작동 순서도

 JDBC 실습 코드

// JdbcApplication.java

package com.thesun4sky.jdbc;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class JdbcApplication {

    public static void main(String[] args) throws SQLException {
        // 어플리케이션 실행 컨텍스트 생성
        SpringApplication.run(JdbcApplication.class, args);

        // 데이터베이스 연결정보
        String url = "jdbc:h2:mem:test";    // spring.datasource.url
        String username = "sa";          // spring.datasource.username

        // connection 얻어오기
        try (Connection connection = DriverManager.getConnection(url, username, null)) {
            try {
                // 테이블 생성 (statement 생성)
                String creatSql = "CREATE TABLE USERS (id SERIAL, username varchar(255))";
                try (PreparedStatement statement = connection.prepareStatement(creatSql)) {
                    statement.execute();
                }

                // 데이터 추가 (statement 생성)
                String insertSql = "INSERT INTO USERS (username) VALUES ('teasun kim')";
                try (PreparedStatement statement = connection.prepareStatement(insertSql)) {
                    statement.execute();
                }

                // 데이터 조회 (statement 생성 후 rs = resultSet 수신 & next() 조회)
                String selectSql = "SELECT * FROM USERS";
                try (PreparedStatement statement = connection.prepareStatement(selectSql)) {
                    var rs = statement.executeQuery();
                    while (rs.next()) {
                        System.out.printf("%d, %s", rs.getInt("id"), rs.getString("username"));
                    }
                }
            } catch (SQLException e) {
                if (e.getMessage().equals("ERROR: relation \"account\" already exists")) {
                    System.out.println("USERS 테이블이 이미 존재합니다.");
                } else {
                    throw new RuntimeException();
                }
            }
        }
    }
}