Post

JDBC 구현

JDBCManager

JDBC를 사용해 Mysql 데이터베이스와의 연결을 관리하는 매니저 클래스


Mysql 데이터베이스 접속에 필요한 정보(사용자이름, 암호, URL) 를 상수로 정의
1
2
3
    private static final String USERNAME = "root";  // 데이터베이스 사용자 이름
    private static final String PASSWORD = "XXXXXXXX";  // 데이터베이스 암호
    private static final String URL = "jdbc:mysql://localhost/XXX?useSSL=false";
  • JDBC URL: localhost에 설치된 MySQL 서버의 XXX데이터베이스에 접속
  • useSSL=false : SSL 을 사용하지 않음
  • 이외 추가 접속 옵션 설정


클래스가 로드될 때 JDBC 드라이버 로드
1
2
3
4
5
6
7
8
9
static {    // 클래스가 로드될때 드라이버가 항상 로드되도록 보장하기 위해 정적으로 설정함(필수X)
    try {
        // Mysql JDBC 드라이버 클래스 로드
        Class.forName("com.mysql.cj.jdbc.Driver");
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
        throw new RuntimeException("Failed to load JDBC driver");
    }
}


데이터베이스 연결
1
2
3
  public static Connection getConnection() throws SQLException {
    return DriverManager.getConnection(URL, USERNAME, PASSWORD);
  }
  • getConnection() 메서드 : 데이터베이스 연결을 생성하고 반환
  • DriverManager.getConnection(URL, USERNAME, PASSWORD) 접속정보를 이용해 데이터베이스 연결 요청을 하고 이를 Connection 객체로 반환한다.


JdbcManager.java 전체코드


연결을 했으니까 이제 SQL 쿼리를 실행하는 Java 코드 보겠습니다.

예시로 주문을 insert 하는 쿼리

insertOrder메서드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class ItemDao {
  public int insertOrder(String itemId, int quantity, Order order) {
    String sql = "INSERT INTO orders (order_id, item_id, stock_count) VALUES (?, ?, ?)";
    try (Connection conn = JdbcManager.getConnection();
         PreparedStatement pstmt = conn.prepareStatement(sql)) {

      // Order 객체에서 필요한 정보를 가져와서 SQL 문에 설정합니다.
      // 주문 insert
      pstmt.setString(1, order.getOrderId());
      pstmt.setString(2, itemId);
      pstmt.setInt(3, quantity);

      int count = pstmt.executeUpdate();

      // 코드 생략


    } catch (SQLException e) {
      e.printStackTrace();
      // 예외 처리 및 롤백 로직이 필요할 수 있음
    }
    return 0;
  }
}
  • 쿼리문 작성 : String sql = “~~~”
    ?은 PreparedStatement의 매개변수 위치 지정자이다.

  • Connection conn = JdbcManager.getConnection();
    JdbcManager 클래스의 getConnection() 메서드를 사용하여 데이터베이스와 연결한다.

  • PreparedStatement pstPreparedStatement pstmt = conn.prepareStatement(sql)
    준비된 문장을 사용하여 SQL 쿼리를 실행할 PreparedStatement 객체를 생성한다.

  • pstmt.setString(1, order.getOrderId());
    Sql 쿼리의 첫 번째 매개변수에 값을 바인딩한다.

  • pstmt.executeUpdate()
    sql 쿼리를 실행하고 데이터베이스에 데이터를 삽입한다.


executeUpdate()와 executeQuery()

하나 기억할 점은 각각 데이터 조작 및 조회 작업에 맞게 sql문 실행 메서드를 사용해야 한다. executeUpdate() 메서드는 insert, update, delete 와 같은 DML 쿼리를 실행할 때 사용된다. 반환값으로 영향을 받은 레코드, 행의 개수를 반환한다.

executeQuery() 메서드는 select 쿼리와 같이 데이터베이스 에서 데이터를 조회할 때 사용한다. ResultSet 객체를 반환하며, ResultSet 는 쿼리에 대한 결과 집합을 나타낸다.


?

하지만 이런 형식으로 select, insert, update 메서드를 구현한다며?

커넥션을 획득하고, 매개변수를 매핑하고, 쿼리를 실행하는 동작들이 중복될 것이다. 중복이 너무 많다~~~

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public abstract class BaseDao<T> {

    public <T> T execute(String sql,
                          ResultSetHandler<T> handler,
                          Object...params) {
        try (Connection conn = JdbcManager.getConnection();
             PreparedStatement pstmt = conn.prepareStatement(sql)) {

            for (int i=0; i<params.length; i++) {
                pstmt.setObject(i+1, params[i]);
            }

            ResultSet rs = pstmt.executeQuery();
            
            return handler.handle(rs);
        
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return null;
    }
}

제네릭 타입 T를 받는 추상 클래스로 다양한 유형의 데이터를 처리할 수 있다.

  • execute() 는 제네릭 메서드로 데이터베이스 쿼리를 실행하고 그 결과를 처리기 위한 메서드
    • sql : 실행할 쿼리문
    • handler : ResultSet 을 처리할 ResultSetHandler 인터페이스 구현체
    • params : 쿼리에 바인딩할 매개변수.


사용 예시
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class ItemDao extends BaseDao {
  public Item selectOne(String id) {
    String sql = "SELECT * FROM item WHERE item_id = ?";

    return (Item) execute(sql, rs -> {
      if (rs.next()) {
        Item item = new Item();
        item.setId(rs.getString("item_id"));
        item.setName(rs.getString("item_nm"));
        item.setPrice(rs.getInt("price"));
        item.setStockCount(rs.getInt("stock_count"));
        return item;
        
      } else {
        return null;
        
      }
    }, id);
  }
}


1
2
3
4
5
6
@FunctionalInterface
public interface ResultSetHandler<T> {

    T handle(ResultSet rs) throws SQLException;;

}
This post is licensed under CC BY 4.0 by the author.