JDBC

컨테이너·2025년 11월 16일
0

SpringFramework

목록 보기
3/15
post-thumbnail

JDBC(Java Database Connectivity)는 자바 프로그램이 데이터베이스와 통신할 수 있도록 해주는 표준 인터페이스(규약)이다. 쉽게 말해, 자바와 DB의 통역사 역할을 한다고 보면 된다.

1. DriverManager

키워드
DB 드러이버 등록 + Connection 생성 담당

  • 역할
    • JDBC드라이버를 로딩하고, connection 객체를 만들어 주는 클래스
  • 드라이버 등록
    Class.forName("com.mysql.cj.jdbc.Driver");
    • Class.forName() : 풀클래스명으로 클래스를 메모리에 올림(동적 로딩)
  • Connection 얻기
    Connection con = DriverManager.getConnection(
            "jdbc:mysql://localhost/{DB이름}"{, 
            "username}", 
            "password}"
     );
  • 주의사항
    • DriverManager는 직접 new를 못하고 getConnection 만 사용한다.

2. Properties 를 이용한 DB 설정 분리

키워드
설정 파일로 DB configuration을 메인 파일과 분리한다.

  • jdbc-config.properties 예시

    driver=com.mysql.cj.jdbc.Driver
    url=jdbc:mysql://localhost/{DB이름}
    user={username}
    password={password}
  • 사용 코드

    Properties prop = new Properties();
    prop.load(new FileReader("jdbc-config.properties"));
    
    String driver = prop.getProperty("driver");
    String url = prop.getProperty("url");
    String user = prop.getProperty("user");
    String password = prop.getProperty("password");
    
    Class.forName(driver);
    Connection con = DriverManager.getConnection(url, user, password);

3. Connection

키워드
DB와의 연결(세션) + Statement/PreparedStatement 생성

  • 역할
    • 특정 DB와의 연결된 "세션" 객체
    • createConnection(), prepareStatement()로 쿼리 실행 객체 생성
  • 예시
    Connection con = DriverManager.getConnection(...);
    Statement stmt = con.createStatement();
    OR
    PreparedStatement pstmt = con.prepareStatement(sql);
  • 자원 반납
    if (con != null && !con.isClosed()) {
        con.close();
    }

4. JDBCTemplate

키워드
반복되는 코드들 모아서 재사용. Connection, close, commit/rollback 의 try/catch 문 등 작성하기 귀찮은 코드 여기에서 메소드화.

  • 예시 코드

    public class JDBCTemplate {
    
      public static Connection getConnection(){
    
          Properties prop = new Properties();
          Connection con = null;
    
          try {
              prop.load(new FileReader(
                      "src/main/java/com/ohgiraffers/crud/config/jdbc-info.properties"
              ));
              String url = prop.getProperty("url");
              con = DriverManager.getConnection(url, prop);
    
              // 자동 커밋 설정을 수동 커밋 설정으로 변경하여 서비스에서 트랜잭션을 컨트롤 할 수 있도록해준다.
              con.setAutoCommit(false);
    
          } catch (IOException | SQLException e) {
              throw new RuntimeException(e);
          }
    
          return con;
      }
    
      /* Connection을 닫는 개념은 별도의 메소드로 분리하고 실제 담는 시점은 Service 계층에서 진행 */
      public static void close(Connection con){
          try {
              if(con != null && !con.isClosed()) con.close();
          } catch (SQLException e) {
              throw new RuntimeException(e);
          }
      }
    
      public static void close(Statement stmt){
          try {
              if(stmt != null && !stmt.isClosed()) stmt.close();
          } catch (SQLException e) {
              throw new RuntimeException(e);
          }
      }
    
      public static void close(ResultSet rset){
          try {
              if(rset != null && !rset.isClosed()) rset.close();
          } catch (SQLException e) {
              throw new RuntimeException(e);
          }
      }
    
      public static void commit(Connection con){
          try {
              if(con != null && !con.isClosed()) con.commit();
          } catch (SQLException e) {
              throw new RuntimeException(e);
          }
      }
    
      public static void rollback(Connection con){
          try {
              if(con != null && !con.isClosed()) con.rollback();
          } catch (SQLException e) {
              throw new RuntimeException(e);
          }
      }
    }
  • 핵심

    • setAutoCommit(false) 자동커밋(비활성화)
    • Service 계층에서 commit() / rollback() 직접 호출

5. Statementj

키워드
완성된 SQL 문자열 실행. 정적 쿼리문 다루며, Injection 공격에 취약하다는 단점을 가짐

  • 특징
    • 완성된 쿼리 문자열을 그대로 DB로 보냄
    • 매번 쿼리를 파싱/컴파일함 → 느릴 수 있고 SQL Injection에 취약함.
  • 생성
    Statement stmt con.createStatement();
  • 사용
    String query = SELECT id, last_name FROM empdb";
    ResultSet rset = stmt.executeQuery(query);
    
    while(rset.next) {
        System.out.prinln(rset.getString("id") + ", " + rset.getString("last_name"));
    }
  • DML 예시(executeUpdate)
    String query = "UPDATE empdb SET last_name = "KIM" WHERE id = '10000'";
    int result = stmt.executeUpdate(query);

6. PreparedStatement

키워드
미완성 쿼리(동적 쿼리) + ? placeholder. 빠르고 안전함

6-1. 특징

  • PreparedStatement도 Statement의 한 종류
  • 미완성 쿼리에 ? 로 플레이스홀더 사용
  • SQL Injection 방어 가능

6-2. 사용 패턴

  1. 미완성 쿼리 문자열 작성
    String sql = "INSERT INTO member VALUES(?, ?)";
  2. PreparedStatement 생성
    PreparedStatement pstmt = con.prepareStatement(sql);
  3. 값 바인딩
    pstmt.setString(1, id);
    pstmt.setString(2, password);
  4. 실행
    • Select → executeQuery()
    • INSERT / UPDATE / DELETE → executeUpdate()
    int result = pstmt.executeUpdate();

6-3. SQL Injection 방어 예시

  • Statement 사용(취약)

    String empId = "200";
    String empName = "' or 1=1 and emp_id = '200";
    
    String query = "SELECT * FROM employee WHERE emp_id = '"
           + empId + "'and emp_name = '" + empName + "'";
  • PreparedStatement 사용
    문자열 안에 ' 있어도 값으로 취급하여 공격 실패

7. ResultSet

키워드
SELECT 결과 집합

  • 역할
    • SELECT 수행 결과 행들을 담는 객체
  • 주요 메소드
    rset.next();
    ↳ 다음 행으로 커서 이동, 있으면 true반환
    rset.getString("emp_id");
    ↳ 현재 행의 컬럼 값
    rset.getInt("menu_price");
    ↳ 자료형에 맞는 getXXX()
  • 기본 패턴
    while(rset.next()) {
        System.out.println(
            rset.getStirng("emp_id") + ", " + 
            rset.getString("emp_name")
        );
    }
  • 사용 후
    rset.close()
    로 자원 반납

8. JDBD에서 DML + 트랜잭션

키워드
SELECT 는 ResultSet, 나머지는 int, commit/rollback

  • SELECT
    ResultSet rset = pstmt.executeQuery();
  • INSERT / UPDATE / DELETE
    int result = pstmt.executeUpdate();
    // 성공한 행의 수 반환
  • 트랜잭션 흐름(Service 계층)
    Connection con = getConnection();
    int result = repoistory.insertMent(con, menu);
    
    if (result > 0) {
        commit(con);
    } else {
        rollback(con);
    }
    close(con);

    9. SQL을 XML/Properties로 분리하는 작업

    키워드
    쿼리를 XML/Properties 파일에 따로 저장해서 관리
  • XML 예시(MenuMapper.xml)
  <?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
<properties>
    <comment/>
    <entry key="insertMenu">
        INSERT
        INTO tbl_menu
        (menu_name, menu_price, category_code, orderable_status)
        VALUES
        (?, ?, ?, ?)
    </entry>
</properties>
  • Repository에서 위 xml 파일 꺼내와 사용

    Properties prop = new Properties();
    prop.loadFromXML(new FileInputStream(".../MenuMapper.xml"));
    
    String sql = prop.getProperty("insertMenu");
    PreparedStatement pstmt = con.prepareStatement(sql);
    
    pstmt.setString(1, menu.getMenuName());
    pstmt.setInt(2, menu.getMenuPrice());
    pstmt.setInt(3, menu.getMenuCode());
    pstmt.setString(4, menu.getOrderableStatus());
    
    int result = pstmt.executeUpdate();

10. 3계층 구조 (View – Service – Repository – DB)

키워드: 역할 분리

  • View (예: main, 콘솔 입력/출력)
    • 사용자에게 입력 받고, Service 호출
  • Service
    • Connection 생성
    • 비즈니스 로직
    • commit / rollback
  • Repository (DAO)
    • 실제 SQL 실행 (CRUD)
    • PreparedStatement, ResultSet 사용
  • DB
    • 테이블

11. JDBC 흐름 정리

드라이버 로딩 → Connection 획득 → Statement/PreparedStatement 생성 → SQL 실행 → ResultSet 처리 → 트랜잭션 처리(commit/rollback) → 자원 반납(close)

profile
백엔드

0개의 댓글