프리페어드 스테이트먼트

위키백과, 우리 모두의 백과사전.

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

프리페어드 스테이트먼트의 일반적인 워크플로는 다음과 같다:

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

소프트웨어 지원[편집]

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

[편집]

자바 JDBC[편집]

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
$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[편집]

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

C# ADO.NET[편집]

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[편집]

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:   SELECT * FROM users WHERE USERNAME=:1 AND PASSWORD=:2
Input Arguments:
1:  username
2:  password

각주[편집]

  1. Oracle. “20.9.4. C API Prepared Statements”. 《MySQL 5.5 Reference Manual》. 2017년 6월 30일에 원본 문서에서 보존된 문서. 2012년 3월 27일에 확인함. 
  2. “13 Oracle Dynamic SQL”. 《Pro*C/C++ Precompiler Programmer's Guide, Release 9.2》. Oracle. 2011년 9월 25일에 확인함. 
  3. “Using the PREPARE and EXECUTE statements”. 《i5/OS Information Center, Version 5 Release 4》. IBM. 2011년 9월 25일에 확인함. [깨진 링크(과거 내용 찾기)]
  4. “SQL Server 2008 R2: Preparing SQL Statements”. 《MSDN Library》. Microsoft. 2011년 9월 25일에 확인함. 
  5. “PREPARE”. 《PostgreSQL 9.5.1 Documentation》. PostgreSQL Global Development Group. 2016년 2월 27일에 확인함.