데이터베이스

Prepared Statement에 대해 알아보겠습니다.

forward error correction Circle 2024. 7. 5. 08:53
반응형

Ⅰ. Prepared Statement란?

데이터베이스에서 반복적으로 실행될 SQL 쿼리를 미리 준비하고 컴파일하여 성능을 최적화하고 보안을 강화하는 기법입니다. SQL 인젝션 공격을 효과적으로 방지하며, 반복 실행되는 쿼리의 성능을 최적화합니다. 플레이스홀더를 사용하여 쿼리를 매개변수화함으로써 코드의 가독성과 유지보수성을 높일 수 있습니다. 다양한 프로그래밍 언어와 데이터베이스 시스템에서 지원되므로, 이를 적극 활용하여 안전하고 효율적인 데이터베이스 접근을 구현할 수 있습니다.

 

Ⅱ.  Prepared Statement 특징

ⅰ. 미리 컴파일된 쿼리
 SQL 쿼리가 데이터베이스 서버에 전달되면, 서버는 쿼리를 컴파일하고 최적화된 실행 계획을 생성합니다.
준비된 쿼리는 여러 번 실행될 때 재컴파일되지 않고, 이미 컴파일된 실행 계획을 사용합니다.
ⅱ. 플레이스홀더 사용
 쿼리에서 값을 직접 사용하는 대신, 플레이스홀더(또는 바인드 변수)를 사용합니다.
예를 들어, SELECT * FROM users WHERE username = ?와 같이 ?가 플레이스홀더 역할을 합니다.
실행 시점에 이 플레이스홀더에 실제 값을 바인딩합니다.

ⅲ. 재사용 가능
 동일한 쿼리를 여러 번 실행할 때, 매번 쿼리를 컴파일할 필요 없이, 준비된 쿼리를 재사용할 수 있습니다.
이는 데이터베이스 서버의 부하를 줄이고, 성능을 향상시킵니다.

 

Ⅲ. Prepared Statement 장점

ⅰ. 보안 강화
 1) SQL 인젝션 방지: 플레이스홀더를 사용하여 쿼리를 작성하면, 입력 값이 SQL 쿼리의 일부분으로 해석되지 않습니다. 이는 SQL 인젝션 공격을 효과적으로 방지합니다.
 2) 입력 값 검증: 데이터베이스 드라이버가 입력 값을 적절하게 이스케이프 처리하므로, 악의적인 입력 값으로부터 보호됩니다.
ⅱ. 성능 향상
 1) 쿼리 컴파일 오버헤드 감소: 동일한 쿼리를 여러 번 실행할 때, 매번 쿼리를 컴파일하지 않아도 되므로 성능이 향상됩니다.
 2) 효율적인 자원 사용: 준비된 쿼리는 캐시에 저장되므로, 자원을 효율적으로 사용합니다.
ⅲ. 코드 가독성 및 유지보수성 향상
 1) 명확한 쿼리 구조: 플레이스홀더를 사용하여 쿼리를 작성하면, 쿼리 구조가 명확해지고, 코드 가독성이 향상됩니다.
 2) 매개변수화된 쿼리: 매개변수화된 쿼리를 사용하면, 쿼리와 데이터가 명확히 분리되므로, 유지보수가 용이해집니다.

 

Ⅳ. 사용예제

 ⅰ. Java(JDBC)

// SQL 쿼리를 준비합니다.
String query = "SELECT * FROM users WHERE username = ? AND password = ?";

try (Connection conn = DriverManager.getConnection(DB_URL, USER, PASS);
       PreparedStatement pstmt = conn.prepareStatement(query)){

       // 플레이스홀더에 값을 바인딩합니다.
      pstmt.setString(1, "exampleUsername");
      pstmt.setString(2, "examplePassword");

      // 쿼리를 실행합니다.
      try (ResultSet rs = pstmt.executeQuery()) {
         while (rs.next()) { System.out.println("User ID: " + rs.getInt("id"));
         }
      }
} catch (SQLException e) {
     e.printStackTrace();
}

 

  ⅱ. Python (SQLite)

import sqlite3

# 데이터베이스 연결
conn = sqlite3.connect('example.db')
cursor = conn.cursor()

# SQL 쿼리를 준비합니다.
query = "SELECT * FROM users WHERE username = ? AND password = ?"

# 플레이스홀더에 값을 바인딩하고 쿼리를 실행합니다.
cursor.execute(query, ("exampleUsername", "examplePassword"))

# 결과를 가져옵니다.
rows = cursor.fetchall()
for row in rows:
    print(row)

# 연결을 닫습니다.
conn.close()

 

반응형