프리페어드 스테이트먼트

**프리페어드 스테이트먼트**(prepared statement), **파라미터라이즈드 스테이트먼트**(parameterized statement)는 데이터베이스 관리 시스템(DBMS)에서 동일하거나 비슷한 데이터베이스 문을 높은 효율성으로 반복적으로 실행하기 위해 사용되는 기능이다. 일반적으로 쿼리나 업데이트와 같은 SQL 문과 함께 사용되는 프리페어드 스테이트먼트는 템플릿의 형태를 취하며, 그 템플릿 안으로 특정한 상수값이 매 실행 때마다 대체된다.

프리페어드 스테이트먼트의 일반적인 워크플로는 다음과 같다:
# **준비**(Prepare): 먼저 애플리케이션은 문의 틀을 만들고 이를 DBMS로 보낸다. 특정값은 지정하지 않은 채로 남겨지며 이들은 "변수", "플레이스홀더", "바인드값"으로 부른다. (아래의 "?" 레이블 참고):
#: 
# 그 다음, DBMS는 문의 틀을 컴파일하며(최적화 및 변환) 아직 실행하지 않고 결과만 저장한다.
# **실행**(Execute): 나중에 애플리케이션이 문 틀의 변수에 값(바인드)을 지정하면 DBMS는 (결과를 반환할 수도 있는) 문을 실행한다. 애플리케이션은 여러 값으로 원하는 횟수만큼 문을 실행할 수 있다. 위의 예에서 첫 번째 변수로 "bike"로, 두 번째 변수로 "10900"을 지정한다.

## 소프트웨어 지원
MySQL, 오라클, DB2, 마이크로소프트 SQL 서버, PostgreSQL을 포함한 주요 DBMS들은 프리페어드 스테이트먼트를 폭넓게 지원한다.

## 예
### 자바 JDBC

```java
import com.mysql.jdbc.jdbc2.optional.MysqlDataSource;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

public class Main {

  public static void main(String[] args) throws SQLException {
    MysqlDataSource ds = new MysqlDataSource();
    ds.setDatabaseName("mysql");
    ds.setUser("root");

    try (Connection conn = ds.getConnection()) {
      try (Statement stmt = conn.createStatement()) {
        stmt.executeUpdate("CREATE TABLE IF NOT EXISTS products (name VARCHAR(40), price INT)");
      }

      try (PreparedStatement stmt = conn.prepareStatement("INSERT INTO products VALUES (?, ?)")) {
        stmt.setString(1, "bike");
        stmt.setInt(2, 10900);
        stmt.executeUpdate();
        stmt.setString(1, "shoes");
        stmt.setInt(2, 7400);
        stmt.executeUpdate();
        stmt.setString(1, "phone");
        stmt.setInt(2, 29500);
        stmt.executeUpdate();
      }

      try (PreparedStatement stmt = conn.prepareStatement("SELECT * FROM products WHERE name = ?")) {
        stmt.setString(1, "shoes");
        ResultSet rs = stmt.executeQuery();
        rs.next();
        System.out.println(rs.getInt(2));
      }
    }
  }
}
```


### PHP PDO

```php
<?php
$stmt = null;

try {
  $conn = new PDO("mysql:dbname=mysql", "root");
  $conn->exec("CREATE TABLE IF NOT EXISTS products (name VARCHAR(40), price INT)");
  $stmt = $conn->prepare("INSERT INTO products VALUES (?, ?)");
  $params = array(array("bike", 10900),
                  array("shoes", 7400),
                  array("phone", 29500));
  foreach ($params as $param) $stmt->execute($param);
  $stmt = $conn->prepare("SELECT * FROM products WHERE name = ?");
  $params = array("shoes");
  $stmt->execute($params);
  echo $stmt->fetch()[1];
} finally {
  if ($stmt !== null) $stmt->closeCursor();
}
?>
```


### 펄 DBI

```perl
my $stmt = $db->prepare("SELECT * FROM users WHERE USERNAME = ? AND PASSWORD = ?");
$stmt->execute($username, $password);
```


### C# ADO.NET

```csharp
using (SqlCommand command = connection.CreateCommand())
{
    command.CommandText = "SELECT * FROM users WHERE USERNAME = @username AND ROOM = @room";
    command.Parameters.AddWithValue("@username", username);
    command.Parameters.AddWithValue("@room", room);

    using (SqlDataReader dataReader = command.ExecuteReader())
    {
        // ...
    }
}
```


### 파이썬 DB-API

```python
import mysql.connector

conn = None
cursor = None

try:
    conn = mysql.connector.connect(database="mysql", user="root")
    cursor = conn.cursor()
    cursor.execute("CREATE TABLE IF NOT EXISTS products (name VARCHAR(40), price INT)")
    params = [("bike", 10900),
              ("shoes", 7400),
              ("phone", 29500)]
    cursor.executemany("INSERT INTO products VALUES (%s, %s)", params)
    params = ("shoes",)
    cursor.execute("SELECT * FROM products WHERE name = %s", params)
    print(cursor.fetchall()[0][1])
finally:
    if cursor is not None: cursor.close()
    if conn is not None: conn.close()
```


### 매직 다이렉트 SQL
 Virtual username  Alpha 20   init: 'sister'
 Virtual password  Alpha 20   init: 'yellow'

 SQL Command:   
```sql
SELECT * FROM users WHERE USERNAME=:1 AND PASSWORD=:2
```


 Input Arguments:
 1:  username
 2:  password

## 같이 보기
* 코드 인젝션
## 각주

분류:데이터베이스
분류:SQL