JDBC(

mskimdev·2026년 5월 19일

Java Library

목록 보기
5/5

JDBC — Java로 데이터베이스에 연결하기

SQL을 배우고 나면 자연스럽게 드는 생각이 있다. "그럼 Java 코드에서는 어떻게 데이터베이스에 접근하지?"

그 물음에 대한 답이 JDBC다.


JDBC란

JDBC(Java Database Connectivity)는 Java 애플리케이션이 데이터베이스와 통신할 수 있게 해주는 표준 API다. Java가 제공하는 인터페이스 집합이고, 실제 동작은 각 데이터베이스 벤더가 제공하는 드라이버(Driver) 가 담당한다.

MySQL을 쓰든, Oracle을 쓰든, PostgreSQL을 쓰든 코드 구조는 동일하다. 드라이버만 바꾸면 된다. 이게 JDBC가 인터페이스 기반으로 설계된 이유다.


동작 흐름

JDBC로 데이터베이스를 다루는 흐름은 항상 일정하다.

  1. 드라이버 로드 — 사용할 DB의 드라이버 클래스를 JVM에 등록
  2. 연결(Connection) 획득 — DB 주소, 계정, 비밀번호로 접속
  3. Statement 생성 — SQL을 실행할 객체 준비
  4. SQL 실행 — 쿼리를 날리고 결과를 받아옴
  5. 자원 닫기 — Connection, Statement, ResultSet 순서로 반드시 닫기

기본 예제

MySQL에 접속해서 데이터를 조회하는 코드다.

import java.sql.*;

public class JdbcExample {
    public static void main(String[] args) {
        String url = "jdbc:mysql://localhost:3306/mydb";
        String user = "root";
        String password = "1234";

        Connection conn = null;
        Statement stmt = null;
        ResultSet rs = null;

        try {
            // 드라이버 로드 (JDBC 4.0부터는 생략 가능)
            Class.forName("com.mysql.cj.jdbc.Driver");

            // 연결 획득
            conn = DriverManager.getConnection(url, user, password);

            // Statement 생성 및 SQL 실행
            stmt = conn.createStatement();
            rs = stmt.executeQuery("SELECT id, name FROM members");

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

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // 자원 닫기 (역순으로)
            try { if (rs != null) rs.close(); } catch (SQLException e) { e.printStackTrace(); }
            try { if (stmt != null) stmt.close(); } catch (SQLException e) { e.printStackTrace(); }
            try { if (conn != null) conn.close(); } catch (SQLException e) { e.printStackTrace(); }
        }
    }
}

ResultSet은 SQL 결과를 행(row) 단위로 읽어오는 객체다. rs.next()를 호출할 때마다 다음 행으로 커서가 이동하고, 더 이상 행이 없으면 false를 반환한다.


Statement vs PreparedStatement

위 예제에서 Statement를 사용했는데, 실제로는 PreparedStatement 를 쓰는 경우가 훨씬 많다.

// Statement — SQL을 문자열로 직접 이어붙임
String sql = "SELECT * FROM members WHERE name = '" + inputName + "'";
stmt = conn.createStatement();
rs = stmt.executeQuery(sql);
// PreparedStatement — ? 자리에 값을 따로 바인딩
String sql = "SELECT * FROM members WHERE name = ?";
PreparedStatement pstmt = conn.prepareStatement(sql);
pstmt.setString(1, inputName);
rs = pstmt.executeQuery();

Statement는 SQL을 문자열로 직접 조합하기 때문에 입력값에 따라 SQL 구조 자체가 바뀔 수 있다. 이게 바로 SQL 인젝션(SQL Injection) 취약점이다. PreparedStatement는 값을 별도로 바인딩해서 이 문제를 원천 차단한다. 이 차이 하나만으로도 PreparedStatement를 기본으로 쓸 이유는 충분하다.


INSERT / UPDATE / DELETE 실행

executeQuery()는 SELECT에만 쓴다. 데이터를 변경하는 쿼리는 executeUpdate()를 사용하고, 반환값은 영향받은 행(row) 수다.

String sql = "INSERT INTO members (name, age) VALUES (?, ?)";
PreparedStatement pstmt = conn.prepareStatement(sql);
pstmt.setString(1, "김자바");
pstmt.setInt(2, 25);

int affected = pstmt.executeUpdate();
System.out.println("삽입된 행 수: " + affected);

try-with-resources로 자원 닫기

finally 블록에서 자원을 하나씩 닫는 코드는 길고 실수하기 쉽다. Java 7부터는 try-with-resources 문법으로 이를 깔끔하게 처리할 수 있다.

String url = "jdbc:mysql://localhost:3306/mydb";

try (Connection conn = DriverManager.getConnection(url, "root", "1234");
     PreparedStatement pstmt = conn.prepareStatement("SELECT id, name FROM members");
     ResultSet rs = pstmt.executeQuery()) {

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

} catch (SQLException e) {
    e.printStackTrace();
}

try 블록이 끝나면 AutoCloseable을 구현한 객체들이 자동으로 닫힌다. Connection, Statement, ResultSet 모두 해당된다.


JDBC URL 구조

jdbc:mysql://localhost:3306/mydb 이 문자열이 처음엔 낯설게 느껴진다.

jdbc:mysql://localhost:3306/mydb?useSSL=false&serverTimezone=UTC
  │     │        │        │    │
  │     │        │        │    └── 추가 옵션 (쿼리 파라미터)
  │     │        │        └─────── 데이터베이스 이름
  │     │        └──────────────── 포트 번호
  │     │        호스트 주소
  │     └───────────────────────── 드라이버 종류 (mysql, oracle, postgresql 등)
  └─────────────────────────────── JDBC 식별자

로컬 개발 환경에서는 localhost:3306이 기본이고, 운영 환경에서는 실제 서버 주소로 바꾼다.


Maven으로 드라이버 추가하기

JDBC 드라이버는 JDK에 포함되어 있지 않다. MySQL을 쓴다면 MySQL Connector/J를 별도로 추가해야 한다.

Maven 프로젝트라면 pom.xml에 의존성을 추가한다.

<dependency>
    <groupId>com.mysql</groupId>
    <artifactId>mysql-connector-j</artifactId>
    <version>8.3.0</version>
</dependency>

JDBC의 한계와 그 다음

JDBC를 직접 쓰면 연결, 예외 처리, 자원 해제를 매번 반복해야 한다. SQL 한 줄을 실행하는데 코드가 20줄 이상 필요하기도 하다.

이런 반복을 줄이기 위해 등장한 것이 MyBatisJPA 같은 도구다. MyBatis는 SQL은 직접 작성하되 JDBC 반복 코드를 제거해주고, JPA는 SQL 자체를 거의 쓰지 않도록 객체와 테이블을 매핑해준다.

JDBC를 이해해두면 이런 도구들이 내부적으로 무슨 일을 하는지 파악하는 데 도움이 된다.


JDBC는 Java와 데이터베이스를 잇는 가장 기본적인 다리다. 드라이버를 로드하고, 연결을 열고, SQL을 실행하고, 자원을 닫는 이 흐름만 머릿속에 있으면 된다.

profile
<- 개발 공부하는 나

0개의 댓글