앞으로 티스토리 대신 blog.stackframe.dev에서 블로깅을 합니다. 이 블로그는 남겨 둘 예정입니다.
이전의 PDO로 데이터베이스 접속하기에 이어 이번에는 PDO를 사용하여 쿼리를 보내어 보겠습니다.
쿼리하는 방법으로는 크게 2가지 방법이 있는데, 첫 번째는 단순하게 완성된 SQL문을 보내서 결과를 받는 것과 Prepared statement로 코드 단에서 SQL문의 뼈대만 먼저 보내고 이후에 조건에 들어가는 인자들을 넘기는 것으로 SQL을 실행하는 방법이 있습니다. 여기서는 이 2가지 방법을 모두 설명할 예정입니다.
PHP에서 PDO로 DBMS에 접속하는 방법에 대해서는 이전 글을 참조하시기 바랍니다.
예제를 보는게 가장 이해하기 쉬우니 간단한 테이블을 하나 만들고 입력, 조회하는 PHP 코드를 만들어 보겠습니다.
<?php
include 'dbconn.php';
$pdo->query('CREATE TABLE IF NOT EXISTS test_table (idx integer, value text)');
$pdo->query('TRUNCATE test_table');
$insert_data_stmt = $pdo->prepare('INSERT INTO test_table (idx,value) VALUES (:idx,:value)');
for($i = 0;$i < 5;$i++)
{
$insert_data_stmt->bindValue(':idx',$i,PDO::PARAM_INT);
$insert_data_stmt->bindValue(':value','bindValue('.$i.')',PDO::PARAM_STR);
$insert_data_stmt->execute();
}
$select_data_stmt = $pdo->prepare('SELECT * FROM test_table ORDER BY idx ASC');
$select_data_stmt->execute();
$result = $select_data_stmt->fetchAll(PDO::FETCH_ASSOC);
echo '==========<br>';
foreach($result as $row)
{
echo $row['idx'], ' = ', $row['value'],'<br>';
}
echo '==========<br><br>';
$idx = 0;
$value = '';
$insert_data_stmt = $pdo->prepare('INSERT INTO test_table (idx,value) VALUES (?,?)');
$insert_data_stmt->bindParam(1,$idx,PDO::PARAM_INT);
$insert_data_stmt->bindParam(2,$value,PDO::PARAM_STR);
for($i = 5;$i < 10;$i++)
{
$idx = $i;
$value = 'bindParam('.$i.')';
$insert_data_stmt->execute();
}
$select_data_stmt->execute();
$result = $select_data_stmt->fetchAll(PDO::FETCH_ASSOC);
echo '==========<br>';
foreach($result as $row)
{
echo $row['idx'], ' = ', $row['value'],'<br>';
}
echo '==========<br><br>';
$select_odd_stmt = $pdo->prepare('SELECT * FROM test_table WHERE idx % ? = 1 ORDER BY idx');
$select_odd_stmt->bindValue(1,2);
$select_odd_stmt->execute();
$result = $select_odd_stmt->fetchAll(PDO::FETCH_ASSOC);
echo '==========<br>';
foreach($result as $row)
{
echo $row['idx'], ' = ', $row['value'],'<br>';
}
echo '==========<br><br>';
실행 결과는 아래와 같습니다.
dbconn.php는 PDO로 데이터베이스 접속하기의 코드가 들어있습니다.
먼저 test_table 테이블이 없다면 테이블을 생성합니다. 컬럼은 idx와 value 2개 입니다. $pdo 객체의 query() 메소드를 사용하면 인자로 주어진 SQL문이 바로 실행됩니다. 이 메소드는 prepared statement가 아니므로 사용자가 입력한 값이 사용된다면 이스케이핑을 해야합니다.
그리고 TRUNCATE로 테이블을 비웁니다.
다음은 $insert_data_stmt 변수에 $pdo의 prepare() 메소드의 결과값을 저장합니다. prepare() 메소드는 prepared statement를 만드는 메소드입니다. 인자에는 SQL문이 들어갑니다만 :idx와 :value라는 이상한 값이 있습니다. 이 2개의 값은 바로 밑 for문 안의 bindValue()메소드에서 실제로 들어가는 값이 입력됩니다.
for문에서 bindValue로 :idx와 :value에 대한 값을 넣어주고 execute() 메소드로 실행하여 쿼리를 실행합니다.
이렇게 동일한 구조의 SQL을 실행한다면 prepared statement로 만들고 bind 후에 execute하는 것만 반복적으로 하면 되므로 DB단에서도 속도를 높힐 수 있고 코드에서도 복잡도가 줄어듭니다.
$select_data_stmt 변수에는 테이블 전체 데이터를 idx 오름차순 정렬해서 가져오는 prepared statement가 들어갑니다. 따로 들어갈 변수가 없으므로 그대로 execute()하면 실행됩니다. 그리고 데이터를 가져오기위해 fetchAll() 메소드를 사용하고 PDO::FETCH_ASSOC이란 값을 인자로 사용합니다. PDO::FETCH_*은 데이터를 어떻게 가져올건가를 지정합니다. 자세한 설명은 여기에 있습니다. 예제에서는 PDO::FETCH_ASSOC을 사용했으니 아래와 같은 모습의 데이터가 $result에 저장됩니다.
Array
(
[0] => Array
(
[idx] => 0
[value] => bindValue(0)
)
[1] => Array
(
[idx] => 1
[value] => bindValue(1)
)
[2] => Array
(
[idx] => 2
[value] => bindValue(2)
)
[3] => Array
(
[idx] => 3
[value] => bindValue(3)
)
[4] => Array
(
[idx] => 4
[value] => bindValue(4)
)
)
다음으로는 또 insert하는 구문이 있습니다. 다만 이번에는 :idx, :value가 아닌 ?로 되어있고 bindValue가 아닌 bindParam 메소드가 사용되었습니다. 그리고 bindParam은 단 한번만 실행되고 for문 안에는 $idx와 $value 변수의 값만 변경한 뒤에 execute()합니다.
먼저 bindParam()의 첫 번째 인자는 위의 bindValue와 동일합니다. 다만 prepare 때 변수 정의 방법이 달라짐으로 인해 이번에는 숫자가 인자로 들어간 것입니다. 만약 prepare()에서 ?만으로 변수를 지정했다면 bindValue나 bindParam에서는 순서대로 1,2,3,4...로 입력해야 합니다. 첫 번째 insert 때처럼 문자로 변수를 지정하면 그 문자를 bindValue나 bindParam의 첫 번째 인자로 넣어줍니다.
bindParam은 변수의 참조를 두 번째 인자로 받습니다. C++의 참조를 생각하시면 됩니다. 그러므로 참조한 변수의 값이 바뀌면 execute()때 바뀐 값이 사용됩니다.
insert가 끝난 뒤에 $select_data_stmt을 다시 execute()하는데, 이걸보면 prepared statement를 사용하면 재사용성이 높아지는걸 알 수 있습니다.
마지막으로 select 하는 것도 위의 설명을 읽어보시면 간단히 이해가 되실겁니다.
'PHP' 카테고리의 다른 글
[PHP] PDO로 데이터베이스 접속하기 (0) | 2019.04.29 |
---|---|
htmlspecialchars로 XSS 공격 방어하기 (0) | 2018.12.23 |