자바

자바 JDBC

thebasics 2024. 8. 31. 17:00

목차
1. JDBC란 무엇인가?
2. JDBC의 필요성
3. JDBC 아키텍처
   - JDBC 드라이버 매니저
   - JDBC 드라이버
   - JDBC 연결 절차
4. JDBC를 사용한 데이터베이스 연결
   - JDBC 드라이버 설정
   - 데이터베이스 연결
   - 기본 SQL 작업
5. PreparedStatement와 Statement의 차이
   - Statement 개념 및 사용법
   - PreparedStatement 개념 및 사용법
6. 트랜잭션 관리
   - 트랜잭션의 개념
   - 트랜잭션 처리 방법
7. ResultSet의 사용
   - ResultSet의 개념
   - ResultSet 사용 예제
8. JDBC 예외 처리
   - SQLException
   - SQLWarning
9. 자원 관리: Connection, Statement, ResultSet
   - 자원 해제의 중요성
   - try-with-resources 사용
10. JDBC와 Connection Pooling
11. 예제와 분석
12. 결론 및 추가 학습 자료


1. JDBC란 무엇인가?

JDBC(Java Database Connectivity)는 자바 애플리케이션이 다양한 데이터베이스에 연결하여 SQL 쿼리를 실행하고, 결과를 처리할 수 있도록 하는 API입니다. JDBC는 자바 애플리케이션과 데이터베이스 간의 상호작용을 표준화하며, 데이터베이스 독립적인 방식으로 데이터베이스 작업을 수행할 수 있게 해줍니다.


2. JDBC의 필요성

자바 애플리케이션이 데이터베이스와 통신하려면, 데이터베이스의 특정 API를 사용해야 합니다. 그러나 이러한 방식은 데이터베이스에 종속적인 코드를 작성하게 만들어, 특정 데이터베이스에서만 동작하도록 제한됩니다. JDBC는 이 문제를 해결하기 위해 등장했으며, 데이터베이스에 독립적인 코드를 작성할 수 있도록 합니다. 이를 통해 애플리케이션은 다양한 데이터베이스에서 동작할 수 있게 됩니다.


3. JDBC 아키텍처

JDBC는 다양한 구성 요소로 이루어져 있으며, 이들은 자바 애플리케이션과 데이터베이스 간의 통신을 담당합니다.

JDBC 드라이버 매니저

JDBC 드라이버 매니저는 데이터베이스와의 연결을 관리하는 역할을 합니다. 애플리케이션에서 데이터베이스와 연결할 때, 적절한 드라이버를 선택하고, 이를 통해 연결을 설정합니다.

JDBC 드라이버

JDBC 드라이버는 자바 애플리케이션과 특정 데이터베이스 간의 상호작용을 가능하게 합니다. 각 데이터베이스 벤더는 자사의 데이터베이스에 맞는 JDBC 드라이버를 제공합니다. JDBC 드라이버는 주로 네 가지 유형으로 나뉩니다: 
1. JDBC-ODBC 브리지 드라이버
2. 네이티브 API 드라이버
3. 네트워크 프로토콜 드라이버
4. 순수 자바 드라이버

JDBC 연결 절차

JDBC를 사용하여 데이터베이스와 연결하는 기본 절차는 다음과 같습니다:
1. JDBC 드라이버 로드
2. 데이터베이스 연결
3. SQL 쿼리 실행
4. 결과 처리
5. 연결 종료


4. JDBC를 사용한 데이터베이스 연결

JDBC를 사용하여 데이터베이스에 연결하고, 기본적인 SQL 작업을 수행하는 방법을 살펴보겠습니다.

JDBC 드라이버 설정

먼저, 데이터베이스 벤더에서 제공하는 JDBC 드라이버를 설정해야 합니다. 일반적으로 '.jar' 파일 형태로 제공되며, 프로젝트에 포함시키거나 클래스패스에 추가해야 합니다.

예제 코드:

// MySQL JDBC 드라이버 로드
Class.forName("com.mysql.cj.jdbc.Driver");

설명:
- 'Class.forName()' 메서드를 사용하여 JDBC 드라이버를 로드합니다.

데이터베이스 연결

데이터베이스에 연결하려면, 'DriverManager.getConnection()' 메서드를 사용하여 'Connection' 객체를 생성합니다.

예제 코드:

String url = "jdbc:mysql://localhost:3306/mydatabase";
String username = "root";
String password = "password";

try (Connection connection = DriverManager.getConnection(url, username, password)) {
    System.out.println("Connected to the database!");
} catch (SQLException e) {
    e.printStackTrace();
}

설명:
- 'DriverManager.getConnection()' 메서드를 사용하여 데이터베이스와의 연결을 설정하고, 'Connection' 객체를 반환합니다.
- 'try-with-resources' 구문을 사용하여 'Connection'을 자동으로 종료합니다.

기본 SQL 작업

기본적인 SQL 작업에는 'SELECT', 'INSERT', 'UPDATE', 'DELETE'와 같은 쿼리를 실행하는 것이 포함됩니다. JDBC에서는 'Statement' 또는 'PreparedStatement' 객체를 사용하여 SQL 쿼리를 실행할 수 있습니다.

예제 코드 (SELECT 쿼리):

String query = "SELECT * FROM users";

try (Statement statement = connection.createStatement();
     ResultSet resultSet = statement.executeQuery(query)) {

    while (resultSet.next()) {
        int id = resultSet.getInt("id");
        String name = resultSet.getString("name");
        String email = resultSet.getString("email");

        System.out.println("ID: " + id + ", Name: " + name + ", Email: " + email);
    }
} catch (SQLException e) {
    e.printStackTrace();
}

설명:
- 'Statement' 객체를 사용하여 SQL 쿼리를 실행하고, 'ResultSet' 객체를 통해 결과를 처리합니다.
- 'resultSet.next()' 메서드는 다음 행으로 이동하며, 결과가 존재하면 'true'를 반환합니다.


5. PreparedStatement와 Statement의 차이

Statement 개념 및 사용법

'Statement' 객체는 단순한 SQL 쿼리를 실행할 때 사용됩니다. 그러나 SQL 쿼리 내에 매개변수가 포함된 경우, 'Statement'는 SQL 인젝션 공격에 취약할 수 있습니다.

PreparedStatement 개념 및 사용법

'PreparedStatement' 객체는 SQL 쿼리를 미리 컴파일하여, 매개변수를 동적으로 설정할 수 있는 기능을 제공합니다. 이는 SQL 인젝션 공격을 방지하고, 성능을 향상시킵니다.

예제 코드 (PreparedStatement 사용):

String query = "INSERT INTO users (name, email) VALUES (?, ?)";

try (PreparedStatement preparedStatement = connection.prepareStatement(query)) {
    preparedStatement.setString(1, "John Doe");
    preparedStatement.setString(2, "john.doe@example.com");
    int rowsAffected = preparedStatement.executeUpdate();

    System.out.println("Rows inserted: " + rowsAffected);
} catch (SQLException e) {
    e.printStackTrace();
}

설명:
- 'PreparedStatement'를 사용하여 매개변수를 설정하고, SQL 쿼리를 실행합니다.
- 'executeUpdate()' 메서드는 데이터베이스에 영향을 미친 행 수를 반환합니다.


6. 트랜잭션 관리

트랜잭션의 개념

트랜잭션은 데이터베이스에서 하나 이상의 작업을 일관되게 처리하는 단위입니다. 트랜잭션은 ACID(원자성, 일관성, 고립성, 지속성) 속성을 보장하며, 여러 작업을 하나의 트랜잭션으로 묶어서 처리할 수 있습니다.

트랜잭션 처리 방법

JDBC에서 트랜잭션을 처리하려면, 'Connection' 객체의 자동 커밋 모드를 비활성화하고, 명시적으로 트랜잭션을 커밋하거나 롤백할 수 있습니다.

예제 코드:

try {
    connection.setAutoCommit(false); // 자동 커밋 비활성화

    String query1 = "UPDATE accounts SET balance = balance - 100 WHERE account_id = 1";
    String query2 = "UPDATE accounts SET balance = balance + 100 WHERE account_id = 2";

    try (Statement statement = connection.createStatement()) {
        statement.executeUpdate(query1);
        statement.executeUpdate(query2);

        connection.commit(); // 트랜잭션 커밋
        System.out.println("Transaction committed successfully!");
    } catch (SQLException e) {
        connection.rollback(); // 트랜잭션 롤백
        System.out.println("Transaction rolled back.");
        e.printStackTrace();
    }
} catch (SQLException e) {
    e.printStackTrace();
}

설명:
- 'setAutoCommit(false)'를 호출하여 자동 커밋을 비활성화합니다.
- 여러 SQL 쿼리를 실행하고, 성공 시 'commit()'을 호출하여 트랜잭션을 커밋합니다.
- 예외 발생 시 'rollback()'을 호출하여 트랜잭션을 롤백합니다.


7. ResultSet의 사용

ResultSet의 개념

'ResultSet'은 SQL 쿼리의 결과를 저장하고, 데이터베이스에서 반환된 결과를 처리할 수 있는 객체입니다. 'ResultSet'은 커서를

 통해 결과 집합을 순차적으로 탐색할 수 있습니다.

ResultSet 사용 예제

예제 코드:

String query = "SELECT * FROM products";

try (Statement statement = connection.createStatement();
     ResultSet resultSet = statement.executeQuery(query)) {

    while (resultSet.next()) {
        int id = resultSet.getInt("id");
        String name = resultSet.getString("name");
        double price = resultSet.getDouble("price");

        System.out.println("ID: " + id + ", Name: " + name + ", Price: " + price);
    }
} catch (SQLException e) {
    e.printStackTrace();
}

설명:
- 'ResultSet'을 사용하여 SQL 쿼리 결과를 반복하면서 각 행의 데이터를 처리합니다.
- 'getInt()', 'getString()', 'getDouble()' 등의 메서드를 사용하여 각 열의 데이터를 읽습니다.


8. JDBC 예외 처리

JDBC 작업 중에는 다양한 예외가 발생할 수 있으며, 이를 적절히 처리해야 합니다.

SQLException

'SQLException'은 JDBC에서 발생하는 예외를 나타내는 기본 클래스입니다. 이 예외는 데이터베이스 연결 오류, SQL 구문 오류, 데이터 무결성 제약 조건 위반 등 다양한 이유로 발생할 수 있습니다.

예제 코드:

try (Connection connection = DriverManager.getConnection(url, username, password)) {
    // 데이터베이스 작업
} catch (SQLException e) {
    System.out.println("SQLState: " + e.getSQLState());
    System.out.println("Error Code: " + e.getErrorCode());
    System.out.println("Message: " + e.getMessage());
    e.printStackTrace();
}

설명:
- 'SQLException'의 'getSQLState()', 'getErrorCode()', 'getMessage()' 메서드를 사용하여 예외의 세부 정보를 출력합니다.

SQLWarning

'SQLWarning'은 심각하지 않은 SQL 경고를 나타내며, 이는 'SQLException'과 달리 예외를 발생시키지 않습니다. 이러한 경고는 주로 성능 문제나 잠재적인 문제가 있을 때 발생합니다.

예제 코드:

try (Connection connection = DriverManager.getConnection(url, username, password)) {
    SQLWarning warning = connection.getWarnings();
    while (warning != null) {
        System.out.println("SQL Warning:");
        System.out.println("State: " + warning.getSQLState());
        System.out.println("Message: " + warning.getMessage());
        System.out.println("Error Code: " + warning.getErrorCode());
        warning = warning.getNextWarning();
    }
} catch (SQLException e) {
    e.printStackTrace();
}

설명:
- 'getWarnings()' 메서드를 사용하여 경고를 확인하고, 이를 처리합니다.


9. 자원 관리: Connection, Statement, ResultSet

자원 해제의 중요성

JDBC에서 사용된 자원(예: 'Connection', 'Statement', 'ResultSet')은 사용 후 반드시 해제해야 합니다. 이를 해제하지 않으면 메모리 누수나 데이터베이스 연결 부족 등의 문제가 발생할 수 있습니다.

try-with-resources 사용

자원을 안전하게 해제하기 위해, 'try-with-resources' 구문을 사용하여 자원을 자동으로 해제할 수 있습니다.

예제 코드:

try (Connection connection = DriverManager.getConnection(url, username, password);
     Statement statement = connection.createStatement();
     ResultSet resultSet = statement.executeQuery("SELECT * FROM users")) {

    while (resultSet.next()) {
        System.out.println(resultSet.getString("name"));
    }
} catch (SQLException e) {
    e.printStackTrace();
}

설명:
- 'try-with-resources' 구문을 사용하여 'Connection', 'Statement', 'ResultSet' 자원을 자동으로 해제합니다.


10. JDBC와 Connection Pooling

Connection Pooling 개념

'Connection Pooling'은 데이터베이스 연결을 미리 생성하여 풀(pool)에 보관하고, 필요할 때마다 재사용하는 기법입니다. 이를 통해 데이터베이스 연결 시간을 절약하고, 성능을 향상시킬 수 있습니다. 자바에서는 다양한 Connection Pooling 라이브러리(예: HikariCP, C3P0)를 사용할 수 있습니다.

예제 코드 (HikariCP 사용):

import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;

import java.sql.Connection;
import java.sql.SQLException;

public class ConnectionPoolingExample {
    private static HikariDataSource dataSource;

    static {
        HikariConfig config = new HikariConfig();
        config.setJdbcUrl("jdbc:mysql://localhost:3306/mydatabase");
        config.setUsername("root");
        config.setPassword("password");
        config.setMaximumPoolSize(10);

        dataSource = new HikariDataSource(config);
    }

    public static Connection getConnection() throws SQLException {
        return dataSource.getConnection();
    }

    public static void main(String[] args) {
        try (Connection connection = getConnection()) {
            System.out.println("Connection acquired from pool!");
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

설명:
- 'HikariCP'를 사용하여 Connection Pool을 구성하고, 데이터베이스 연결을 풀에서 가져와 사용합니다.


11. 예제와 분석

지금까지 배운 JDBC 개념들을 종합적으로 적용한 예제를 살펴보겠습니다.

종합 예제:

import java.sql.*;

public class JDBCDemo {
    private static final String URL = "jdbc:mysql://localhost:3306/mydatabase";
    private static final String USERNAME = "root";
    private static final String PASSWORD = "password";

    public static void main(String[] args) {
        try (Connection connection = DriverManager.getConnection(URL, USERNAME, PASSWORD)) {
            // 데이터 삽입
            String insertQuery = "INSERT INTO users (name, email) VALUES (?, ?)";
            try (PreparedStatement preparedStatement = connection.prepareStatement(insertQuery)) {
                preparedStatement.setString(1, "Alice");
                preparedStatement.setString(2, "alice@example.com");
                int rowsInserted = preparedStatement.executeUpdate();
                System.out.println("Rows inserted: " + rowsInserted);
            }

            // 데이터 조회
            String selectQuery = "SELECT * FROM users";
            try (Statement statement = connection.createStatement();
                 ResultSet resultSet = statement.executeQuery(selectQuery)) {

                while (resultSet.next()) {
                    int id = resultSet.getInt("id");
                    String name = resultSet.getString("name");
                    String email = resultSet.getString("email");

                    System.out.println("ID: " + id + ", Name: " + name + ", Email: " + email);
                }
            }

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

코드 분석:
- 데이터베이스 연결을 설정하고, 'PreparedStatement'를 사용하여 데이터를 삽입합니다.
- 'Statement'와 'ResultSet'을 사용하여 데이터를 조회하고, 결과를 처리합니다.


12. 결론 및 추가 학습 자료

이번 글에서는 자바의 JDBC를 사용하여 데이터베이스에 연결하고, SQL 작업을 수행하는 방법에 대해 살펴보았습니다. JDBC는 자바 애플리케이션이 데이터베이스와 상호작용할 수 있게 해주는 강력한 도구로, 이를 잘 활용하면 다양한 데이터베이스 작업을 효율적으로 수행할 수 있습니다.

추가 학습 자료:
- 자바 공식 문서: [Oracle Java Documentation - JDBC](https://docs.oracle.com/javase/tutorial/jdbc/)
- 온라인 자바 튜토리얼: [W3Schools Java JDBC](https://www.w3schools.com/java/)
- 자바 코딩 연습 사이트: [GeeksforGeeks - JDBC in Java](https://www.geeksforgeeks.org/introduction-to-jdbc/)

JDBC는 자바 프로그래밍에서 중요한 역할을 하며, 데이터베이스와의 상호작용을 관리하는 핵심 기술입니다. 이번 기회를 통해 JDBC의 개념과 활용 방법을 잘 이해하고, 실무에서 효과적으로 사용해보세요.


이제 자바의 JDBC에 대해 자세히 이해하게 되었습니다. 다음 글에서는 자바의 또 다른 고급 기능에 대해 다루도록 하겠습니다. 자바의 더 깊은 이해를 위해 계속해서 학습해나가세요!

반응형

'자바' 카테고리의 다른 글

자바 Autoboxing and Unboxing  (6) 2024.09.02
자바 Enum (열거형)  (0) 2024.09.01
자바 애너테이션  (2) 2024.08.30
자바 네트워킹  (0) 2024.08.29
자바 동기화  (2) 2024.08.28