[Spring] JDBC

배창민·2025년 10월 1일
post-thumbnail

JDBC


0) 구성요소 역할 요약

컴포넌트핵심 역할비고/주의
DriverManagerJDBC 드라이버 로딩, DB 연결(Connection) 생성Class.forName() 동적 로딩, getConnection()
ConnectionDB와의 실제 연결, SQL 실행 객체 생성createStatement(), prepareStatement()
Statement완성된 SQL 실행매 실행 시 파싱/컴파일 발생
PreparedStatement파라미터 바인딩( ? ) 지원, 재사용빠름·안전(SQL Injection 방어)
ResultSetSELECT 결과 표(테이블) 커서next(), getXxx(), 반드시 close()

1) DriverManager

1-1) 드라이버 로딩 & 연결

// 1) 드라이버 로딩 (동적 로딩)
Class.forName("com.mysql.cj.jdbc.Driver");  // ClassNotFoundException 처리

// 2) 연결 생성
Connection con = DriverManager.getConnection(
    "jdbc:mysql://localhost/employee", "ohgiraffers", "ohgiraffers"); // SQLException 처리

1-2) Properties로 설정 분리

jdbc-config.properties

driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost/employee
user=ohgiraffers
password=ohgiraffers

로드 & 연결

Properties prop = new Properties();
prop.load(new FileReader("jdbc-config.properties"));

Class.forName(prop.getProperty("driver"));
Connection con = DriverManager.getConnection(
        prop.getProperty("url"),
        prop.getProperty("user"),
        prop.getProperty("password"));

설정을 분리하면 오타/중복/유지보수 비용을 줄일 수 있음.


2) Connection (생성·반납 공통화 팁)

  • 반드시 사용 후 반납
  • 중복되는 연결/반납 코드는 템플릿 유틸로 공통화
public class JDBCTemplate {
    public static Connection getConnection() {
        // properties 로드 & DriverManager.getConnection() ..
        return /* con */;
    }
    public static void close(Connection con) {
        try { if (con != null && !con.isClosed()) con.close(); }
        catch (SQLException e) { e.printStackTrace(); }
    }
}

실무/과제에서는 try-with-resources가 더 깔끔.


3) Statement vs PreparedStatement

3-1) Statement (완성 SQL)

Statement stmt = con.createStatement();
ResultSet rs = stmt.executeQuery("SELECT id, last_name FROM emp");
while (rs.next()) {
    System.out.println(rs.getString("id") + ", " + rs.getString("last_name"));
}

3-2) PreparedStatement (위치홀더 ?)

  • 장점

    1. 속도: 한 번 파싱/컴파일 → 재사용(바인딩 값만 교체)
    2. 보안: 값과 SQL을 분리해 SQL Injection 방어
String sql = "INSERT INTO member (id, password) VALUES (?, ?)";
try (PreparedStatement pstmt = con.prepareStatement(sql)) {
    pstmt.setString(1, id);       // 1-base index
    pstmt.setString(2, password);
    int updated = pstmt.executeUpdate(); // DML은 executeUpdate()
}

SELECTexecuteQuery() / INSERT·UPDATE·DELETEexecuteUpdate() 를 사용.


4) SQL 외부화 (XML/Properties)

employee-query.xml

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
<properties>
  <entry key="selectEmpByFamilyName">
    SELECT e.* FROM employee e
    WHERE e.emp_name LIKE CONCAT(?, '%')
  </entry>
</properties>

로드 & 실행

Properties prop = new Properties();
prop.loadFromXML(new FileInputStream("employee-query.xml"));
String sql = prop.getProperty("selectEmpByFamilyName");

try (PreparedStatement pstmt = con.prepareStatement(sql)) {
    pstmt.setString(1, familyName);
    try (ResultSet rs = pstmt.executeQuery()) {
        while (rs.next()) { /* ... */ }
    }
}

5) ResultSet 핵심

  • 커서 이동: next() → 다음 행 존재 시 true
  • 데이터 조회: getString("col"), getInt("col")타입별 getXxx
  • 자원 반납: close()
while (rs.next()) {
    String empId = rs.getString("emp_id");
    String empName = rs.getString("emp_name");
    System.out.println(empId + ", " + empName);
}

6) JDBC 표준 절차(템플릿)

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

// 2) 연결
try (Connection con = DriverManager.getConnection(url, user, password)) {

    // 3) SQL 준비 (Statement or PreparedStatement)
    String sql = "UPDATE emp SET last_name = ? WHERE id = ?";
    try (PreparedStatement pstmt = con.prepareStatement(sql)) {

        // 4) 바인딩 & 실행
        pstmt.setString(1, "KIM");
        pstmt.setString(2, "10000");
        int result = pstmt.executeUpdate();

        // 5) 결과 처리 (커밋/로직)
        System.out.println("updated rows = " + result);
    }

    // 6) try-with-resources 덕분에 자동 close
} catch (SQLException e) {
    e.printStackTrace();
}

SELECTexecuteQuery()ResultSet 처리
INSERT/UPDATE/DELETEexecuteUpdate()로 영향 행 수 처리


핵심 정리

  • DriverManager로 연결 만들고 → PreparedStatement빠르고 안전하게 실행 → ResultSet정확히 닫고 처리.
  • 설정/쿼리는 외부 파일에, 연결/반납은 공통 템플릿/try-with-resources중복 제거.
profile
개발자 희망자

0개의 댓글