본문 바로가기
Computing and DB 🖥/Database

[JDBC] - PreparedStatement

by dudefromkorea 2024. 1. 31.
Prepared Statement 란?

SQL Query 를 실행하기 전에 미리 컴파일하고

실행 시에만 파라미터를 전달하는 방식의 SQL 문

 

 

<Prepared Statement 의 이점들>

성능 향상

처음 실행될 때 DB 에 의해 컴파일되고

서버 측에 캐싱하여 같은 Query 가 재사용될 때

재컴파일 하지 않고 이미 컴파일된 Query 를 재활용하므로

반복된 Query 실행 시 컴파일 시간이 단축된다

 

SQL Injection 방지

 파라미터를 '?' 로 표시하고 실행 시점에 값을 바인딩하는 특성상

문자열의 일부로 해석되지 않고 별도의 값으로 처리되기에

사용자의 입력이 쿼리의 논리를 변경할 수 없으므로

SQL Injection 을 차단하는데 효과적이다

 

입력 데이터의 자동 변환

지정된 데이터 타입에 따라 자동으로

입력값을 변환하는 특성을 가지고 있다

예시로 setInt()setString() 메소드 등을 이용하여

적절한 데이터 타입으로 값을 설정할 수 있어 간편하다

 

가독성 및 유지 보수성 향상

Query 와 Java 코드가 분리되어 있으므로

둘 사이의 상호작용을 명확하게 이해할 수 있고

 Query 수정이 필요한 경우 SQL 구문만 수정하면 되기에

유지보수 측면에서 용이하며 코드를 읽고 이해하기 수월하다

 

 

<Prepared Statement 사용 방법>

#1 쿼리 준비

Query 를 작성할 때 나중에 실제 값이

들어갈 위치에 플레이스홀더('?')를 넣어준다

 

 #2 PreparedStatement 생성

DB Connection 을 사용하여

Prepared Statement 객체를 생성한다

 

#3 파라미터 생성

'setXXX()' 메소드를 사용하여

각 플레이스홀더에 해당하는 값을 설정한다

(ex: setInt(), setString(), etc...)

 

#4 Query 실행

executeQuery 나 excecuteUpdate 을 사용하여 Query 를 실행한다

 

executeQuery: ResultSet 객체를 반환하며, 해당 객체를 통해 쿼리의 결과 데이터에 접근할 수 있다. 주로 SELECT 에 사용

PreparedStatement pstmt = conn.prepareStatement("SELECT * FROM table_name WHERE column = ?");
pstmt.setString(1, "value");
ResultSet rs = pstmt.executeQuery();
while (rs.next()) {
    // 후처리 로직
}

 

excecuteUpdate: int 값을 반환하며, 쿼리에 의해 영향을 받은 행의 수를 받는다. 주로 INSERT, UPDATE, DELETE 에 사용

PreparedStatement pstmt = conn.prepareStatement("UPDATE table_name SET column1 = ? WHERE column2 = ?");
pstmt.setString(1, "valueOne");
pstmt.setString(2, "valueTwo");
int affectedRows = pstmt.executeUpdate(); // 2

 

#5 결과 처리

Query 실행 후 후처리 로직을 수행한다

(SELECT 의 경우, ResultSet 을 통해 결과를 처리)

 

#6 자원 해제

사용이 끝난 후에는 자원을 닫고 해제한다

 

 

<Prepared Statement 코드 예시>

PreparedStatement + JDBC 사용 예시

Connection conn = null;
PreparedStatement pstmt = null;
ResultSet rs = null;

try {
    conn = DriverManager.getConnection("jdbc:yourDBMS://yourUrl", "username", "password");
    String sql = "SELECT * FROM users WHERE id = ? AND username = ?";
    pstmt = conn.prepareStatement(sql);

    pstmt.setInt(1, 1); // 첫 번째 플레이스홀더에 값을 1 로 설정
    pstmt.setString(2, "Peter"); // 두 번째 플레이스홀더에 값을 Peter 로 설정

    rs = pstmt.executeQuery();

    while (rs.next()) {
        String name = rs.getString("name");
        // 다른 칼럼 및 후처리 로직...
    }
} catch (SQLException e) {
    e.printStackTrace();
} finally {
    if (rs != null) try { rs.close(); } catch (SQLException e) {}
    if (pstmt != null) try { pstmt.close(); } catch (SQLException e) {}
    if (conn != null) try { conn.close(); } catch (SQLException e) {}
}

 

PreparedStatement + mybatis 사용 예시

SqlSession sqlSession = MyBatisUtil.getSqlSessionFactory().openSession();
try {
    UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
    User user = userMapper.selectUser(1, "Peter");
    // 후처리 로직
} finally {
    sqlSession.close();
}

// mybatis
<mapper namespace="example.mapper.UserMapper">
    <select id="selectUser" resultType="example.User">
        SELECT * FROM users WHERE id = #{id} AND username = #{username}
    </select>
</mapper>

 

 

<주의사항>

예외 처리

SQL 실행 중 발생할 수 있는 예외를 적절히 처리해야 한다

일반적으로 try-catch 블록을 사용하여 SQLException 을 처리한다

 

자원 해제

PreparedStatement, ResultSet, Connection 등을

사용 후에는 반드시 자원을 닫고 해제해야 한다

 

자원 해제는 finally 에서 닫고 해제하는 것이 일반적이다

728x90
반응형

'Computing and DB 🖥 > Database' 카테고리의 다른 글

SQL Injection  (0) 2024.02.02
DB LOCK 에 대해서 알아보자  (0) 2024.01.23
NoSql 이 뭐야?  (0) 2023.12.12
대용량을 대비한 DB... 어떻게 설정해? (feat.PostgreSQL)  (33) 2023.11.14