[2020/12/07] PHP PDO クラスを使用したデータテーブル操作クラスを作成してみました (No.242)
[2020/12/05] PHP PDOStatement クラスの中で使うと思われるメソッド(closeCursor,errorInfo,fetchAll,rowCount)について (No.241)
[2020/12/05] PHP PDO(PHP Data Objects)クラスを使った「AUTO_INCREMENT」カラムの取得について (No.240)
[2020/12/04] PHP PDO(PHP Data Objects)クラスを使ったトランザクションについて (No.239)
[2020/12/04] PHP PDO(PHP Data Objects)クラスを使ったデータベースへのアクセス(登録、更新、削除)について (No.238)
-
×
[PR]上記の広告は3ヶ月以上新規記事投稿のないブログに表示されています。新しい記事を書く事で広告が消えます。
-
PDO 及び PDOStatement クラスを使ったデータベースへの接続からテーブルレコード取得、及びデータレコードに対しての登録・更新・削除、さらにトランザクションについて、以下の記事で説明してきました。
⇒PHP PDO(PHP Data Objects)クラスを使ったデータベースへのアクセスについて
⇒PHP PDO(PHP Data Objects)クラスを使ったデータベースへのアクセス(登録、更新、削除)について
⇒PHP PDO(PHP Data Objects)クラスを使ったトランザクションについて
⇒PHP PDO(PHP Data Objects)クラスを使った「AUTO_INCREMENT」カラムの取得について
⇒PHP PDOStatement クラスの中で使うと思われるメソッド(closeCursor,errorInfo,fetchAll,rowCount)について
そこでこれらの処理を簡単に行える様にするためのクラスを作成してみました。
クラスの中で PDO クラスのインスタンスを生成し、外部から直接 PDO オブジェクトを参照することが無いようにしました。 このクラスのメソッドは以下の様になります。メソッド名 説明 __construct コンストラクタ(データベースへの接続) getLastError 最終発生エラー情報の取得 close データベース接続を閉じる begin トランザクション開始 commit トランザクション・コミット rollback トランザクション・ロールバック prepare [prepare]メソッドのラッパ関数 lastInsertId 最後のAUTOINCREMENTの取得 execute SQLステートメント実行(prepare, bindValue, excute を内部で順次実行) getColumnData SQLステートメント実行し1個のカラム値を取得(自身の execute メソッドを使用) getSelectCount SQLステートメント実行行数の取得(自身の getColumnData メソッドを使用) ■クラスのスクリプト [cPDOMySQL.php]
以下にスクリプトを示します。
データベースの接続用のホスト名などのデフォルト値をこのソースの先頭に記述しています。
本来であれば、別のPHPソースまたは、ini ファイルなどで読込んで指定すべきかと思います。<?php // ===== // MySQLデータベース操作クラス [cPDOMySQL.php] // ===== // デフォルトのDB指定値 define('MYSQL_HOST', 'localhost'); define('MYSQL_DBNAME', 'pdo'); define('MYSQL_CHARSET', 'UTF8'); define('MYSQL_USER', 'root'); define('MYSQL_PASSWORD','password'); class cPDOMySQL { private $pdo; // PDOクラスインスタンス private $host; // 接続先ホスト private $dbname; // データベース名 private $user; // 接続ユーザ private $password; // 接続パスワード private $charset; // キャラクタセット名 // 最終実行SQL private $sql; // 最終発生エラー情報(配列データ) // 配列[0]:SQLSTATE エラーコード (これは、ANSI SQL 標準で定義された英数 5 文字の ID) // 配列[1]:ドライバ固有のエラーコード // 配列[2]:ドライバ固有のエラーメッセージ private $error; // ===== // 最終発生エラー情報の取得 // ===== // [返り値] // array PDO::errorInfo() または PDOStatement::errorInfo() public function getLastError() { return $this->error; } // ===== // コンストラクタ(データベースへの接続) // ===== // [引数] // $host string 接続先ホスト (デフォルト:MYSQL_HOST) // $dbname string データベース名 (デフォルト:MYSQL_DBNAME) // $charset string キャラクタセット名(デフォルト:MYSQL_CHARSET) // $user string 接続ユーザ (デフォルト:MYSQL_USER) // $password string 接続パスワード (デフォルト:MYSQL_PASSWORD) public function __construct($host = MYSQL_HOST, $dbname = MYSQL_DBNAME, $charset = MYSQL_CHARSET, $user = MYSQL_USER, $password = MYSQL_PASSWORD) { // データベース指定値退避 $this->host = trim($host); $this->dbname = trim($dbname); $this->charset = trim($charset); $this->user = trim($user); $this->password = trim($password); // 初期化 $this->sql = ""; $this->clearError(); // データベース接続 try { $dsn = "mysql:host={$this->host};dbname={$this->dbname};charset={$this->charset}"; $this->pdo = new PDO($dsn, $this->user, $this->password); } catch (PDOException $e) { echo 'データベース接続エラー:'.$e->getMessage(); } if ($this->pdo == false) { die("データベースへの接続に失敗しました。"); } } // ===== // エラー情報クリア // ===== protected function clearError() { $this->error = array(0 => null, 1 => null, 2 => null); } // ===== // データベース接続を閉じる // ===== public function close() { $this->pdo = null; } // ===== // トランザクション開始 // ===== public function begin() { return $this->pdo->beginTransaction(); } // ===== // トランザクション・コミット // ===== public function commit() { return $this->pdo->commit(); } // ===== // トランザクション・ロールバック // ===== public function rollback() { return $this->pdo->rollBack(); } // ===== // [prepare]メソッドのラッパ関数 // ===== // [引数] // $sql string SQLステートメント // [返り値] // mixed 正常終了:[PDOStatement]オブジェクト,エラー:false public function prepare($sql) { // エラークリア $this->clearError(); // SQL文の準備 $pdostmt = $this->pdo->prepare($sql); if ($pdostmt === false) { // エラーの場合 $this->error = $pdostmt->errorInfo(); return false; } // [PDOStatement]オブジェクトを返す return $pdostmt; } // ===== // 最後のAUTOINCREMENTの取得 // ===== // [返り値] // mixed 正常終了:最後に挿入された行の[ID]値の文字列 // エラー :false (getLastError()でエラー情報が取得できる) public function lastInsertId() { // エラークリア $this->clearError(); try { $ret = $this->pdo->lastInsertId(); } catch (PDOException $e) { $this->error = $e->errorInfo; $ret = false; } return $ret; } // ===== // SQLステートメント実行 // ===== // [引数] // $sql string SQLステートメント // $arrBind array SQL内のプレースホルダの値の配列 array(':name' => value, ...) // [返り値] // mixed 正常終了:SELECT文の場合[PDOStatement]オブジェクト, // SELECT文以外の場合 true, // エラー :false public function execute($sql, $arrBind = array()) { // SQL準備 $pdostmt = $this->prepare($sql); if ($pdostmt === false) { return false; } // バインド foreach ($arrBind as $key => $val) { $ret = $pdostmt->bindValue($key, $val); if ($ret === false) { $this->error = $pdostmt->errorInfo(); return false; } } // 実行 $ret = $pdostmt->execute(); if ($ret === false) { $this->error = $pdostmt->errorInfo(); return false; } // SELECTステートメントの場合?? if (preg_match('/^select/i', trim($sql))) { // [PDOStatement]オブジェクト return $pdostmt; } else { // selectステートメント以外の場合 return true; } } // ===== // SQLステートメント実行し1個のカラム値を取得 // ===== // [引数] // $sql string SQLステートメント // $arrBind array SQL内のプレースホルダの値の配列 array(':name' => value, ...) // $columnName string カラム名、またはカラムIndex値 // [返り値] // mixed 正常終了:カラムの値 // エラー :false public function getColumnData($sql, $arrBind = array(), $columnName = 0) { // SQLステートメント実行 $pdostmt = $this->execute($sql, $arrBind); if ($pdostmt === false) { return false; } // 1行取得 $row = $pdostmt->fetch(); if ($row === false) { // エラー $this->error = $pdostmt->errorInfo(); $ret = false; } else { // カラムデータ $ret = $row[$columnName]; } // 接続を閉じる $pdostmt = null; // カラムデータを返す return $ret; } // ===== // SQLステートメント実行行数の取得 // ===== // [引数] // $sql string SQLステートメント // $arrBind array SQL内のプレースホルダの値の配列 array(':name' => value, ...) // [返り値] // mixed 正常終了:件数 // エラー :false public function getSelectCount($sql, $arrBind = array()) { // SELECT文を SELECT count(*) でラップ $sql = "select count(*) from ({$sql}) as tx"; // 件数を取得して返します。 return $this->getColumnData($sql, $arrBind); } } ?>
■クラス cPDOMySQL を利用したスクリプト例
cPDOMySQL クラスは bindValue を複数記述するのが面倒だったために、内部で繰り返し処理しています。
ただし、PDOStatement クラスのオブジェクトを取得した後の処理は、cPDOMySQL クラスの呼び出し側で 処理する必要があります。
データ取得後のデータ処理もクラス化するのであれば、このクラスを継承して、その子クラスで処理を行えばよいかと思います。 (突っ込みどころ満載かと思いますので、改変して下さい。)
取敢えず、cPDOMySQL クラスを利用したスクリプトの例を以下に記します。<?php /* [pdoc1.php] */ include "./cPDOMySQL.php"; ob_start(function($buf){ return mb_convert_encoding($buf, 'SJIS', 'UTF-8'); }); // MySQLデータベース操作クラス生成(データベース接続) $pdo = new cPDOMySQL(); // データ取得SQL(名前付きパラメータ) $sqlList = "select * from `tm_shohin` where id >= :id1 and id <= :id2 order by id"; // SELECTクエリのパラメータに実際の値設定と実行 $pdostmt = $pdo->execute($sqlList, array(":id1" => "1", ":id2" => "3")); // PDOStatementクラスの fetch メソッドで1行のデータ取得 while ($result = $pdostmt->fetch()) { // データが取得できた場合(データ表示) echo "id:".$result["id"]." name :".$result["name"]." price:".$result["price"]."\n"; } echo "end...\n"; $ret = $pdo->getSelectCount($sqlList, array(":id1" => "1", ":id2" => "3")); echo "getSelectCount...[$ret]\n"; $ret = $pdo->getColumnData("select now()"); echo "system time...[$ret]\n"; // トランザクション開始 $ret = $pdo->begin(); if ($ret == true) { // トランザクション開始OK try { // レコード登録(INSERT)SQL $sql = "insert into `tm_shohin` (id, name, price) VALUE (:id, :name, :price)"; // SQL文の実行([id:3]のデータ) if ($ret == true) { $arrPara = array(":id" => 3, ":name" => 'パソコン003', ":price" => 303000); $ret = $pdo->execute($sql, $arrPara); } // SQL文の実行([id:4]のデータ) if ($ret == true) { $arrPara = array(":id" => 4, ":name" => 'プリンタ001', ":price" => 50000); $ret = $pdo->execute($sql, $arrPara); } } catch (Exception $e) { // 何かスクリプト上のエラーが在った!! $ret = false; } // トランザクション終了処理 if ($ret == true) { // コミット $pdo->commit(); } else { // ロールバック $pdo->rollback(); } } else { // トランザクション開始NG } // 再度、SELECTクエリのパラメータに実際の値設定と実行 $pdostmt = $pdo->execute($sqlList, array(":id1" => "1", ":id2" => "4")); // PDOStatementクラスの fetch メソッドで1行のデータ取得 while ($result = $pdostmt->fetch()) { // データが取得できた場合(データ表示) echo "id:".$result["id"]." name :".$result["name"]." price:".$result["price"]."\n"; } echo "end...\n"; // 接続を閉じる $pdo->close(); ?>
これを実行すると以下の様に表示されます。
C:\xampp\htdocs\_test>php pdoc1.php id:1 name :パソコン001 price:110000 id:2 name :パソコン002 price:222200 end... getSelectCount...[2] system time...[2020-12-07 18:07:58] id:1 name :パソコン001 price:110000 id:2 name :パソコン002 price:222200 id:3 name :パソコン003 price:303000 id:4 name :プリンタ001 price:50000 end...
PR -
PDO クラスを使ったデータベースへの接続からテーブルレコード取得、及びデータレコードに対しての登録・更新・削除、さらにトランザクションについて、以下の記事で説明してきました。
⇒PHP PDO(PHP Data Objects)クラスを使ったデータベースへのアクセスについて
⇒PHP PDO(PHP Data Objects)クラスを使ったデータベースへのアクセス(登録、更新、削除)について
⇒PHP PDO(PHP Data Objects)クラスを使ったトランザクションについて
⇒PHP PDO(PHP Data Objects)クラスを使った「AUTO_INCREMENT」カラムの取得について
そこで、今回は PDOStatement クラスの中で使うと思われるメソッドについて説明します。
- PDOStatement::closeCursor — カーソルを閉じてステートメントを再実行できるようにする
- PDOStatement::errorInfo — 文ハンドラにおける直近の操作に関連する拡張エラー情報を取得する
- PDOStatement::fetchAll — 全ての結果行を含む配列を返す
- PDOStatement::rowCount — 直近の SQL ステートメントによって作用した行数を返す
■PDOStatement::closeCursor — カーソルを閉じてステートメントを再実行できるようにする
カーソル とはデータ取得SQL(SELECT)を実行し、データをフェッチする時の位置を指し示すポインタの様な概念です。
closeCursor はその カーソル を廃棄し再度のSQL実行を有効とします。 以下にスクリプト例を示します。<?php /* [pdo19.php] */ ob_start(function($buf){ return mb_convert_encoding($buf, 'SJIS', 'UTF-8'); }); // MySQLデータベースに接続 $dsn = "mysql:host=localhost;dbname=pdo;"; $user = 'root'; $password = 'password'; try { // PDOクラス生成(データベース接続) $pdo = new PDO($dsn, $user, $password); } catch (PDOException $e) { // エラー発生 die('データベース接続ERROR:'.$e->getMessage()."\n"); } // 全データ取得SQL $sql = "select * from `tm_shohin` order by id"; // SELECTクエリの準備 $pdostmt = $pdo->prepare($sql); // SELECTクエリの実行 $pdostmt->execute(); // 先頭のデータ取得 $result = $pdostmt->fetch(); // 2番目のデータ取得 $result = $pdostmt->fetch(); echo "id:".$result["id"]." name :".$result["name"]." price:".$result["price"]."\n"; // カーソルクローズ $pdostmt->closeCursor(); // 再度SELECTクエリの実行 $pdostmt->execute(); // 先頭のデータ取得 $result = $pdostmt->fetch(); echo "id:".$result["id"]." name :".$result["name"]." price:".$result["price"]."\n"; // 接続を閉じる $pdo = null; ?>
これを実行すると以下の様に表示されます。 カーソルクローズ後、再度クエリ実行した時に、先頭からフェッチされるのがわかります。
C:\xampp\htdocs\_test>php pdo19.php id:2 name :パソコン002 price:202000 id:1 name :パソコン001 price:100000
■PDOStatement::errorInfo — 文ハンドラにおける直近の操作に関連する拡張エラー情報を取得する
errorInfo メソッドは直前のSQL実行に対してのエラー情報を取得します。
エラー情報は以下の様に配列データ(指標:[0 ~ 2])として返されます。- 情報配列[0]: SQLSTATE エラーコード (これは、ANSI SQL 標準で定義された英数 5 文字の ID)
- 情報配列[1]: ドライバ固有のエラーコード
- 情報配列[2]: ドライバ固有のエラーメッセージ
<?php /* [pdo20.php] */ ob_start(function($buf){ return mb_convert_encoding($buf, 'SJIS', 'UTF-8'); }); // MySQLデータベースに接続 $dsn = "mysql:host=localhost;dbname=pdo;"; $user = 'root'; $password = 'password'; try { // PDOクラス生成(データベース接続) $pdo = new PDO($dsn, $user, $password); } catch (PDOException $e) { // エラー発生 die('データベース接続ERROR:'.$e->getMessage()."\n"); } // 全データ取得SQL:エラーがあるSQL $sql = "select * from `tm_shohin` order by "; // SELECTクエリの準備 $pdostmt = $pdo->prepare($sql); // SELECTクエリの実行 $ret = $pdostmt->execute(); if ($ret === false) { // 実行でエラーが発生したので、エラー情報取得 $arr = $pdostmt->errorInfo(); print_r($arr); } // 接続を閉じる $pdo = null; ?>
これを実行すると以下の様に表示されます。
C:\xampp\htdocs\_test>php pdo20.php Array ( [0] => 42000 [1] => 1064 [2] => You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to us e near '' at line 1 )
■PDOStatement::fetchAll — 全ての結果行を含む配列を返す
fetch メソッドは1行毎のデータを取得しますが、fetch メソッドは全ての結果行を配列で返します。
// fetchメソッド定義 public PDOStatement::fetchAll([ int $fetch_style [, mixed $fetch_argument [, array $ctor_args = array() ]]]):array $fetch_style レコードを呼び出し元に返す方法を制御します。 PDO::FETCH_* 定数のどれかで、デフォルトは PDO::FETCH_BOTH です。 $fetch_argument この引数は、fetch_style の値によって意味が異なります。 PDO::FETCH_COLUMN: ここで指定した、 0 から始まる番号のカラムを返します。 PDO::FETCH_CLASS: ここで指定したクラスのインスタンスを返します。 各行のカラムがクラスのプロパティ名にマッピングされます。 PDO::FETCH_FUNC: ここで指定した関数をコールした結果を返します。 各行のカラムを関数コール時のパラメータとします。 $ctor_args fetch_style が PDO::FETCH_CLASS のときに使う、独自のクラスコンストラクタへの引数。 返り値: 結果セットに残っている全ての行を含む配列を返します。 取得結果がゼロ件だった場合は空の配列を返し、失敗した場合は FALSE を返します。
以下にスクリプトの例を示します。
<?php /* [pdo21.php] */ ob_start(function($buf){ return mb_convert_encoding($buf, 'SJIS', 'UTF-8'); }); // MySQLデータベースに接続 $dsn = "mysql:host=localhost;dbname=pdo;"; $user = 'root'; $password = 'password'; try { // PDOクラス生成(データベース接続) $pdo = new PDO($dsn, $user, $password); } catch (PDOException $e) { // エラー発生 die('データベース接続ERROR:'.$e->getMessage()."\n"); } // 全データ取得SQL:エラーがあるSQL $sql = "select * from `tm_shohin` order by id"; // SELECTクエリの準備 $pdostmt = $pdo->prepare($sql); // SELECTクエリの実行 $pdostmt->execute(); // 全ての行を取得 $arr = $pdostmt->fetchAll(); print_r($arr); // 接続を閉じる $pdo = null; ?>
これを実行すると以下の様に表示されます。
C:\xampp\htdocs\_test>php pdo21.php Array ( [0] => Array ( [id] => 1 [0] => 1 [name] => パソコン001 [1] => パソコン001 [price] => 100000 [2] => 100000 ) [1] => Array ( [id] => 2 [0] => 2 [name] => パソコン002 [1] => パソコン002 [price] => 202000 [2] => 202000 ) [2] => Array ( [id] => 3 [0] => 3 [name] => パソコン003 [1] => パソコン003 [price] => 303000 [2] => 303000 ) [3] => Array ( [id] => 4 [0] => 4 [name] => プリンタ001 [1] => プリンタ001 [price] => 50000 [2] => 50000 ) )
■PDOStatement::rowCount — 直近の SQL ステートメントによって作用した行数を返す
rowCount メソッドは相当する PDOStatement オブジェクトによって実行された 直前の DELETE, INSERT, UPDATE 文によって作用した行数を返します。
尚、SELECT 文によって作用した行数を返さないので、別の方法が必要になります。 (取得するSELECT文をラップして「SELECT COUNT(*)...」するとかでしょうか)<?php /* [pdo22.php] */ ob_start(function($buf){ return mb_convert_encoding($buf, 'SJIS', 'UTF-8'); }); // MySQLデータベースに接続 $dsn = "mysql:host=localhost;dbname=pdo;"; $user = 'root'; $password = 'password'; try { // PDOクラス生成(データベース接続) $pdo = new PDO($dsn, $user, $password); } catch (PDOException $e) { // エラー発生 die('データベース接続ERROR:'.$e->getMessage()."\n"); } // レコード更新(UPDATE)SQL $sql = "update `tm_shohin` set price = price * 1.1 where id >= :id1 and id <= :id2"; // SQL文の準備 $pdostmt = $pdo->prepare($sql); // データ変数設定 $intId1 = 1; $intId2 = 3; // データバインド $pdostmt->bindValue(":id1", $intId1, PDO::PARAM_INT); $pdostmt->bindValue(":id2", $intId2, PDO::PARAM_INT); // SQL文の実行 $ret = $pdostmt->execute(); // 実行行数の取得 $count = $pdostmt->rowCount(); echo "rowCount(): $count \n"; // 接続を閉じる $pdo = null; ?>
これを実行すると以下の様に表示されます。
C:\xampp\htdocs\_test>php pdo22.php rowCount(): 3
-
今回は MySQL の AUTO_INCREMENT の属性が付けられたカラムの値の取得について説明します。
AUTO_INCREMENT 属性を付けられるカラムはデータ型が整数型です。
INSERT SQLにより AUTO_INCREMENT 属性カラムを指定しない場合、順次+1された値が割り当てられます。
以下の様に、テスト用のテーブルを作成します。
「id」と「name」の2つのみのカラムを持ち、「id」に AUTO_INCREMENT を設定します。MariaDB [pdo]> CREATE TABLE `test_auto` ( -> `id` int(11) NOT NULL AUTO_INCREMENT, -> `name` varchar(100) DEFAULT NULL, -> PRIMARY KEY (id) -> ) ENGINE=InnoDB DEFAULT CHARSET=utf8; Query OK, 0 rows affected (0.91 sec) MariaDB [pdo]> show columns from `test_auto`; +-------+--------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +-------+--------------+------+-----+---------+----------------+ | id | int(11) | NO | PRI | NULL | auto_increment | | name | varchar(100) | YES | | NULL | | +-------+--------------+------+-----+---------+----------------+ 2 rows in set (0.05 sec) MariaDB [pdo]>
このテーブルにデータを追加してみます。
MariaDB [pdo]> INSERT INTO `test_auto` (`name`) VALUES ('test001'); Query OK, 1 row affected (0.05 sec) MariaDB [pdo]> select * from `test_auto`; +----+---------+ | id | name | +----+---------+ | 1 | test001 | +----+---------+ 1 row in set (0.00 sec)
MySQL には最後の AUTO_INCREMENT カラムの値を取得できる LAST_INSERT_ID() 関数があります。
MariaDB [pdo]> SELECT LAST_INSERT_ID() FROM `test_auto`; +------------------+ | LAST_INSERT_ID() | +------------------+ | 1 | +------------------+ 1 row in set (0.00 sec)
MySQL の LAST_INSERT_ID() 関数と同じ機能が PDO クラスの lastInsertId メソッドで行えます。
上記の「test_auto」テーブルにデータを登録し、 lastInsertId メソッドを呼出してみます。<?php /* [pdo17.php] */ ob_start(function($buf){ return mb_convert_encoding($buf, 'SJIS', 'UTF-8'); }); // MySQLデータベースに接続 $dsn = "mysql:host=localhost;dbname=pdo;"; $user = 'root'; $password = 'password'; try { // PDOクラス生成(データベース接続) $pdo = new PDO($dsn, $user, $password); } catch (PDOException $e) { // エラー発生 die('データベース接続ERROR:'.$e->getMessage()."\n"); } // レコード登録(INSERT)SQL:[id]は AUTO_INCREMENT なので指定しない $sql = "insert into `test_auto` (name) VALUE (:name)"; // SQL文の準備 $pdostmt = $pdo->prepare($sql); // SQL文の実行 $ret = $pdostmt->execute(array(":name" => 'test002')); // [test_auto.id]の取得 $id = $pdo->lastInsertId(); echo "lastInsertId() = $id \n"; // 接続を閉じる $pdo = null; ?>
これを実行すると以下の様に表示されます。2件目のレコードが追加されたので「id」に「2」が返されるのがわかります。
C:\xampp\htdocs\_test>php pdo17.php lastInsertId() = 2
テーブルの中身を見てみます。
MariaDB [pdo]> select * from `test_auto`; +----+---------+ | id | name | +----+---------+ | 1 | test001 | | 2 | test002 | +----+---------+ 2 rows in set (0.05 sec) MariaDB [pdo]>
この lastInsertId メソッドは、登録した直後のデータの「id」を取得しますが、これの必要な場面とは何があるのでしょうか。
例えば、売上データで、売上ヘッダテーブルと売上明細テーブルを分けて持つ場合です。
売上ヘッダデータと売上明細データは 1:N の関係で、同じ「id」で紐づけられると思います。
最初に売上ヘッダデータを登録し、その直後に lastInsertId メソッドで「id」を取得し、 売上明細にはその「id」と明細の連番で売上明細テーブルに登録するといった手順になると思います。
■トランザクション処理の中の AUTO_INCREMENT について
トランザクション処理の中で1件データを追加し、その後で明示的にエラーが発生するSQL文を実行し、ロールバックを行わせてみます。 以下にそのスクリプトを示します。
<?php /* [pdo18.php] */ ob_start(function($buf){ return mb_convert_encoding($buf, 'SJIS', 'UTF-8'); }); // MySQLデータベースに接続 $dsn = "mysql:host=localhost;dbname=pdo;"; $user = 'root'; $password = 'password'; try { // PDOクラス生成(データベース接続) $pdo = new PDO($dsn, $user, $password); } catch (PDOException $e) { // エラー発生 die('データベース接続ERROR:'.$e->getMessage()."\n"); } // トランザクション開始 $ret = $pdo->beginTransaction(); if ($ret == true) { // トランザクション開始OK try { // レコード登録(INSERT)SQL:[id]は AUTO_INCREMENT なので指定しない $sql = "insert into `test_auto` (name) VALUE (:name)"; $pdostmt = $pdo->prepare($sql); $ret = $pdostmt->execute(array(":name" => 'test003')); // [test_auto.id]の取得 $id = $pdo->lastInsertId(); echo "lastInsertId() = $id \n"; // エラーの発生するレコード登録(INSERT)SQL $sql = "insert into `test_auto` (name) VALUE ()"; $pdostmt = $pdo->prepare($sql); $ret = $pdostmt->execute(); // この時点でエラー発生 } catch (Exception $e) { // 何かスクリプト上のエラーが在った!! $ret = false; } // トランザクション終了処理 if ($ret == true) { // コミット $pdo->commit(); echo "commit() \n"; } else { // ロールバック $pdo->rollback(); echo "rollback() \n"; } // [test_auto.id]の取得 $id = $pdo->lastInsertId(); echo "lastInsertId() = $id \n"; } else { // トランザクション開始NG } // 接続を閉じる $pdo = null; ?>
これを実行すると以下の様に表示されます。 登録実行後、最初の lastInsertId メソッドでは「3」が返されますが、 次の INSERT 処理ではエラーが発生し、ロールバック処理が行われます。 この後で、 lastInsertId メソッドを実行してもトランザクション開始前の状態に戻るため、「0」が返ります。
C:\xampp\htdocs\_test>php pdo18.php lastInsertId() = 3 rollback() lastInsertId() = 0
この状態で、テーブルの属性を SHOW TABLE コマンドで見てみます。MariaDB [pdo]> SHOW TABLE STATUS LIKE 'test_auto'\G *************************** 1. row *************************** Name: test_auto Engine: InnoDB Version: 10 Row_format: Compact Rows: 3 Avg_row_length: 5461 Data_length: 16384 Max_data_length: 0 Index_length: 0 Data_free: 0 Auto_increment: 4 Create_time: 2020-12-04 18:39:53 Update_time: NULL Check_time: NULL Collation: utf8_general_ci Checksum: NULL Create_options: Comment: 1 row in set (0.00 sec)
test_auto の Auto_increment は「4」となり、次の追加処理が行われた時にはその値「4」が設定されます。
トランザクション中に Auto_increment の変化が在ったのですがロールバックしても値は「4」のままとなります。
上記のソースでは「3」の値でINSERTしたのですが、その後のエラーSQLでロールバックされ「3」は欠番となります。
この結果は少し、不都合な感じもしますが、複数のマシンから同じスクリプトが起動され、 それぞれが別々の Auto_increment の値を取る様にするためには必要なことだと思います。
-
PDO を使ったデータベースへの接続とテーブルレコード取得、及びデータレコードに対しての登録(INSERT)、更新(UPDATE)、削除(DELETE)について、以下の記事で説明しました。
⇒PHP PDO(PHP Data Objects)クラスを使ったデータベースへのアクセスについて
⇒PHP PDO(PHP Data Objects)クラスを使ったデータベースへのアクセス(登録、更新、削除)について
そこで、今回はデータ処理に関連して重要な方法であるトランザクション処理について説明します。
トランザクション処理 とは複数実行されるデータの登録(INSERT)、更新(UPDATE)、削除(DELETE)処理を一時的に蓄えておいて、 全ての処理が正常であれば、一括でデータベースに反映させるものです。
尚、どれかの処理でエラーが発生した場合には、全ての処理を取止め、データベースの状態をトランザクション開始の前の状態に戻せます。
トランザクション処理 を行うには以下の PDO クラスのメソッドを使います。- PDO::beginTransaction — トランザクションを開始する
- PDO::commit — トランザクションをコミットする(データベースへの一括反映)
- PDO::rollBack — トランザクションをロールバックする(トランザクション開始以降の処理を廃棄)
これらのメソッドは 返り値 として成功した場合に TRUE を、失敗した場合に FALSE を返します。
トランザクション処理 の実装としては以下の様に行います。(実際の処理では無く日本語で記述しています)// データベースへの接続 $pdo = new PDO( ... ); // トランザクション開始 $ret = $pdo->beginTransaction(); if ($ret == true) { // トランザクション開始が正常の場合 // 複数のデータの登録(INSERT)、更新(UPDATE)、削除(DELETE)の処理 ... if (データ処理が正常チェック) { // 正常の場合 $ret = $pdo->commit(); // コミット処理 } else { // エラーの場合 $ret = $pdo->rollBack(); // ロールバック処理 } } else { // トランザクション開始がエラーの場合 // (必要であれば処理記述) } // 接続を閉じる $pdo = null;
■トランザクション・コミットの例
トランザクション・コミットの例として、最初のテーブルデータを全て削除(DELETE)後、2件のデータを追加(INSERT)します。 最後にコミットを行い、テーブルの全データの一覧を表示します。
<?php ob_start(function($buf){ return mb_convert_encoding($buf, 'SJIS', 'UTF-8'); }); // MySQLデータベースに接続 $dsn = "mysql:host=localhost;dbname=pdo;"; $user = 'root'; $password = 'password'; try { // PDOクラス生成(データベース接続) $pdo = new PDO($dsn, $user, $password); } catch (PDOException $e) { // エラー発生 die('データベース接続ERROR:'.$e->getMessage()."\n"); } // === 全データの取得・表示 === function dispAll($_pdo) { $sql = "select * from `tm_shohin` order by id"; // 全データ取得SQL $pdostmt = $_pdo->prepare($sql); // SELECTクエリの準備 $pdostmt->execute(); // SELECTクエリの実行 while ($result = $pdostmt->fetch()) { echo "id:".$result["id"]." name :".$result["name"]." price:".$result["price"]."\n"; } echo "\n"; } // トランザクション開始 $ret = $pdo->beginTransaction(); // 全レコード削除(UPDATE)SQL $sql = "delete from `tm_shohin`"; // SQL文の準備 $pdostmt = $pdo->prepare($sql); // SQL文の実行 $ret = $pdostmt->execute(); // レコード登録(INSERT)SQL $sql = "insert into `tm_shohin` (id, name, price) VALUE (:id, :name, :price)"; // SQL文の準備 $pdostmt = $pdo->prepare($sql); // SQL文の実行([id:1]のデータ) $ret = $pdostmt->execute(array(":id" => 1, ":name" => 'パソコン001', ":price" => 100000)); // SQL文の実行([id:2]のデータ) $ret = $pdostmt->execute(array(":id" => 2, ":name" => 'パソコン002', ":price" => 202000)); // コミット $ret = $pdo->commit(); // 処理後の表示 dispAll($pdo); // 接続を閉じる $pdo = null; ?>
これを実行すると以下の様に表示されます。2件のレコードが追加されたのがわかります。
C:\xampp\htdocs\_test>php pdo12.php id:1 name :パソコン001 price:100000 id:2 name :パソコン002 price:202000
■トランザクション・ロールバックの例
トランザクション・ロールバックの例として、2件のデータを追加(INSERT)し, 最後にロールバックを行い、テーブルの全データの一覧を表示します。
<?php ob_start(function($buf){ return mb_convert_encoding($buf, 'SJIS', 'UTF-8'); }); // MySQLデータベースに接続 $dsn = "mysql:host=localhost;dbname=pdo;"; $user = 'root'; $password = 'password'; try { // PDOクラス生成(データベース接続) $pdo = new PDO($dsn, $user, $password); } catch (PDOException $e) { // エラー発生 die('データベース接続ERROR:'.$e->getMessage()."\n"); } // === 全データの取得・表示 === function dispAll($_pdo) { $sql = "select * from `tm_shohin` order by id"; // 全データ取得SQL $pdostmt = $_pdo->prepare($sql); // SELECTクエリの準備 $pdostmt->execute(); // SELECTクエリの実行 while ($result = $pdostmt->fetch()) { echo "id:".$result["id"]." name :".$result["name"]." price:".$result["price"]."\n"; } echo "\n"; } // 処理前の表示 dispAll($pdo); // トランザクション開始 $ret = $pdo->beginTransaction(); // レコード登録(INSERT)SQL $sql = "insert into `tm_shohin` (id, name, price) VALUE (:id, :name, :price)"; // SQL文の準備 $pdostmt = $pdo->prepare($sql); // SQL文の実行([id:3]のデータ) $ret = $pdostmt->execute(array(":id" => 3, ":name" => 'パソコン003', ":price" => 303000)); // SQL文の実行([id:4]のデータ) $ret = $pdostmt->execute(array(":id" => 4, ":name" => 'プリンタ001', ":price" => 50000)); // ロールバック $ret = $pdo->rollback(); // 処理後の表示 dispAll($pdo); // 接続を閉じる $pdo = null; ?>
これを実行すると以下の様に表示されます。INSERT 処理されたデータが登録されていないことがわかります。
C:\xampp\htdocs\_test>php pdo13.php id:1 name :パソコン001 price:100000 id:2 name :パソコン002 price:202000 id:1 name :パソコン001 price:100000 id:2 name :パソコン002 price:202000
■トランザクション・コミットせずにスクリプトが終了した場合
上記のスクリプトからロールバックの部分を忘れた状況にしてみます。
<?php ob_start(function($buf){ return mb_convert_encoding($buf, 'SJIS', 'UTF-8'); }); // MySQLデータベースに接続 $dsn = "mysql:host=localhost;dbname=pdo;"; $user = 'root'; $password = 'password'; try { // PDOクラス生成(データベース接続) $pdo = new PDO($dsn, $user, $password); } catch (PDOException $e) { // エラー発生 die('データベース接続ERROR:'.$e->getMessage()."\n"); } // トランザクション開始 $ret = $pdo->beginTransaction(); // レコード登録(INSERT)SQL $sql = "insert into `tm_shohin` (id, name, price) VALUE (:id, :name, :price)"; // SQL文の準備 $pdostmt = $pdo->prepare($sql); // SQL文の実行([id:3]のデータ) $ret = $pdostmt->execute(array(":id" => 3, ":name" => 'パソコン003', ":price" => 303000)); // SQL文の実行([id:4]のデータ) $ret = $pdostmt->execute(array(":id" => 4, ":name" => 'プリンタ001', ":price" => 50000)); // 接続を閉じる //$pdo = null; ?>
これを実行し、MySQLから直接一覧を取ると以下の様に表示されます。INSERT 処理されたデータが登録されていないことがわかります。
MariaDB [pdo]> select * from tm_shohin; +----+-------------+--------+ | id | name | price | +----+-------------+--------+ | 1 | パソコン001 | 100000 | | 2 | パソコン002 | 202000 | +----+-------------+--------+ 2 rows in set (0.00 sec)
これはトランザクションが開始され途中でコミットをせずにスクリプトが終わるとロールバックされるからです。
尚、接続を閉じるための PDO オブジェクトの null 設定を省いていますが、 PDO オブジェクトもスクリプトが終了する時には廃棄されるのと同時に、接続は閉じられます。
■トランザクション・一般的な例
トランザクション処理を行うデータ更新処理の一般的な例としては、以下の様な処理になるかと思います。
<?php ob_start(function($buf){ return mb_convert_encoding($buf, 'SJIS', 'UTF-8'); }); // MySQLデータベースに接続 $dsn = "mysql:host=localhost;dbname=pdo;"; $user = 'root'; $password = 'password'; try { // PDOクラス生成(データベース接続) $pdo = new PDO($dsn, $user, $password); } catch (PDOException $e) { // エラー発生 die('データベース接続ERROR:'.$e->getMessage()."\n"); } // トランザクション開始 $ret = $pdo->beginTransaction(); if ($ret == true) { // トランザクション開始OK try { // レコード登録(INSERT)SQL $sql = "insert into `tm_shohin` (id, name, price) VALUE (:id, :name, :price)"; // SQL文の準備 $pdostmt = $pdo->prepare($sql); // SQL文の実行([id:3]のデータ) if ($ret == true) { $ret = $pdostmt->execute(array(":id" => 3, ":name" => 'パソコン003', ":price" => 303000)); } // SQL文の実行([id:4]のデータ) if ($ret == true) { $ret = $pdostmt->execute(array(":id" => 4, ":name" => 'プリンタ001', ":price" => 50000)); } // その他処理があれば続く... } catch (Exception $e) { // 何かスクリプト上のエラーが在った!! $ret = false; } // トランザクション終了処理 if ($ret == true) { // コミット $pdo->commit(); } else { // ロールバック $pdo->rollback(); } } else { // トランザクション開始NG } // 接続を閉じる $pdo = null; ?>
-
PDO を使ったデータベースへの接続と、テーブルレコード取得を以下の記事で説明しました。
⇒PHP PDO(PHP Data Objects)クラスを使ったデータベースへのアクセスについて
そこで、今回はデータレコードに対しての登録(INSERT)、更新(UPDATE)、削除(DELETE)について説明します。■テーブルレコード登録(INSERT)の例
テーブルにレコード登録を行う場合 prepare メソッドでSQL文を作成し execute メソッドでSQL文を実行します。
今回のSQL文には バインドパラメータ が無いので prepare メソッドは引数無しで実行します。
尚、レコード登録の前後で全データの一覧を表示する関数「dispAll」を宣言しました。<?php ob_start(function($buf){ return mb_convert_encoding($buf, 'SJIS', 'UTF-8'); }); // MySQLデータベースに接続 $dsn = "mysql:host=localhost;dbname=pdo;"; $user = 'root'; $password = 'password'; try { // PDOクラス生成(データベース接続) $pdo = new PDO($dsn, $user, $password); } catch (PDOException $e) { // エラー発生 die('データベース接続ERROR:'.$e->getMessage()."\n"); } // === 全データの取得・表示 === function dispAll($_pdo) { $sql = "select * from `tm_shohin` order by id"; // 全データ取得SQL $pdostmt = $_pdo->prepare($sql); // SELECTクエリの準備 $pdostmt->execute(); // SELECTクエリの実行 while ($result = $pdostmt->fetch()) { echo "id:".$result["id"]." name :".$result["name"]." price:".$result["price"]."\n"; } echo "\n"; } // 登録前の表示 dispAll($pdo); // レコード登録(INSERT)SQL $sql = "insert into `tm_shohin` (id, name, price) VALUE (6, 'プリンタ003', 60000)"; // SQL文の準備 $pdostmt = $pdo->prepare($sql); // SQL文の実行 $pdostmt->execute(); // パラメータが無いので指定しない // 登録後の表示 dispAll($pdo); // 接続を閉じる $pdo = null; ?>
これを実行すると以下の様に表示されます。「id = 6」のレコードが追加されたのがわかります。
C:\xampp\htdocs\_test>php pdo6.php id:1 name :パソコン001 price:100000 id:2 name :パソコン002 price:202000 id:3 name :パソコン003 price:303000 id:4 name :プリンタ001 price:50000 id:5 name :プリンタ002 price:150000 id:1 name :パソコン001 price:100000 id:2 name :パソコン002 price:202000 id:3 name :パソコン003 price:303000 id:4 name :プリンタ001 price:50000 id:5 name :プリンタ002 price:150000 id:6 name :プリンタ003 price:60000
「id = 6」のレコードが存在している状況で、再度レコード登録を行うと、どうなるのでしょうか。
以下のスクリプトを実行してみます。<?php ob_start(function($buf){ return mb_convert_encoding($buf, 'SJIS', 'UTF-8'); }); // MySQLデータベースに接続 $dsn = "mysql:host=localhost;dbname=pdo;"; $user = 'root'; $password = 'password'; try { // PDOクラス生成(データベース接続) $pdo = new PDO($dsn, $user, $password); } catch (PDOException $e) { // エラー発生 die('データベース接続ERROR:'.$e->getMessage()."\n"); } // レコード登録(INSERT)SQL $sql = "insert into `tm_shohin` (id, name, price) VALUE (6, 'プリンタ003', 60000)"; // SQL文の準備 $pdostmt = $pdo->prepare($sql); // SQL文の実行 $ret = $pdostmt->execute(); // 返り値を変数で受ける var_dump($ret); // 接続を閉じる $pdo = null; ?>
これを実行すると以下の様に返り値が false で返されるのが分かります。
上記の登録が正常な場合には true が返されているはずです。 実際の処理においては、返り値で登録が正常または異常かを判断して、その後の処理を行う必要があります。C:\xampp\htdocs\_test>php pdo7.php bool(false)
上のスクリプトは固定のSQL文でしたが、以下に 名前付パラメータ を含むものしたスクリプトを記します。
1回の prepare で複数のデータ実行ができることが分かります。<?php ob_start(function($buf){ return mb_convert_encoding($buf, 'SJIS', 'UTF-8'); }); // MySQLデータベースに接続 $dsn = "mysql:host=localhost;dbname=pdo;"; $user = 'root'; $password = 'password'; try { // PDOクラス生成(データベース接続) $pdo = new PDO($dsn, $user, $password); } catch (PDOException $e) { // エラー発生 die('データベース接続ERROR:'.$e->getMessage()."\n"); } // レコード登録(INSERT)SQL $sql = "insert into `tm_shohin` (id, name, price) VALUE (:id, :name, :price)"; // SQL文の準備 $pdostmt = $pdo->prepare($sql); // SQL文の実行(名前付パラメータのデータを配列で指定) $ret = $pdostmt->execute(array(":id" => 7, ":name" => 'マウス001', ":price" => 3000)); // 準備済みのSQLを利用して別のデータで実行 $ret = $pdostmt->execute(array(":id" => 8, ":name" => 'マウス002', ":price" => 5000)); // 接続を閉じる $pdo = null; ?>
execute メソッドの引数に配列で設定するのではなく、以下の bindValue メソッドを使って各名前付パラメータに値を設定できます。
// bindValueメソッド定義 public PDOStatement::bindValue ( mixed $parameter , mixed $value [, int $data_type = PDO::PARAM_STR ] ) : bool $parameter パラメータ ID。 名前付パラメータを使用するプリペアドステートメントの場合は、:name 形式のパラメータ名となります。 疑問符パラメータを使用するプリペアドステートメントの場合は、1 から始まるパラメータの位置となります。 実行される SQL 文の中のバインドパラメータと同数の要素からなる、値の配列。 $value パラメータにバインドする値。 $data_type パラメータに対して PDO::PARAM_* 定数 を使った明示的なデータ型を指定します。 返り値: 成功した場合に TRUE を、失敗した場合に FALSE を返します。
bindValue メソッドを使ってデータ登録を行うスクリプトを記します。
<?php ob_start(function($buf){ return mb_convert_encoding($buf, 'SJIS', 'UTF-8'); }); // MySQLデータベースに接続 $dsn = "mysql:host=localhost;dbname=pdo;"; $user = 'root'; $password = 'password'; try { // PDOクラス生成(データベース接続) $pdo = new PDO($dsn, $user, $password); } catch (PDOException $e) { // エラー発生 die('データベース接続ERROR:'.$e->getMessage()."\n"); } // レコード登録(INSERT)SQL $sql = "insert into `tm_shohin` (id, name, price) VALUE (:id, :name, :price)"; // SQL文の準備 $pdostmt = $pdo->prepare($sql); // データ変数設定 $intId = 9; $strName = "マウス003"; $intPrice = 7000; // データバインド $pdostmt->bindValue(":id" , $intId , PDO::PARAM_INT); $pdostmt->bindValue(":name" , $strName , PDO::PARAM_STR); $pdostmt->bindValue(":price", $intPrice, PDO::PARAM_INT); // SQL文の実行 $ret = $pdostmt->execute(); // 接続を閉じる $pdo = null; ?>
■テーブルレコード更新(UPDATE)の例
レコートの登録(追加)が一通り終わりましたので、更新に付いて記します。
更新の場合も、登録と同様にSQL文を prepare メソッドで準備し bindValue メソッドを使って名前付パラメータに値を設定後、 execute メソッドでSQLの実行を行います。
以下の更新処理は、「id」が「1」~「3」の「price」を1.1倍にします。<?php ob_start(function($buf){ return mb_convert_encoding($buf, 'SJIS', 'UTF-8'); }); // MySQLデータベースに接続 $dsn = "mysql:host=localhost;dbname=pdo;"; $user = 'root'; $password = 'password'; try { // PDOクラス生成(データベース接続) $pdo = new PDO($dsn, $user, $password); } catch (PDOException $e) { // エラー発生 die('データベース接続ERROR:'.$e->getMessage()."\n"); } // === 全データの取得・表示 === function dispAll($_pdo) { $sql = "select * from `tm_shohin` order by id"; // 全データ取得SQL $pdostmt = $_pdo->prepare($sql); // SELECTクエリの準備 $pdostmt->execute(); // SELECTクエリの実行 while ($result = $pdostmt->fetch()) { echo "id:".$result["id"]." name :".$result["name"]." price:".$result["price"]."\n"; } echo "\n"; } // 更新前の表示 dispAll($pdo); // レコード更新(UPDATE)SQL $sql = "update `tm_shohin` set price = price * 1.1 where id >= :id1 and id <= :id2"; // SQL文の準備 $pdostmt = $pdo->prepare($sql); // データ変数設定 $intId1 = 1; $intId2 = 3; // データバインド $pdostmt->bindValue(":id1", $intId1, PDO::PARAM_INT); $pdostmt->bindValue(":id2", $intId2, PDO::PARAM_INT); // SQL文の実行 $ret = $pdostmt->execute(); // 更新後の表示 dispAll($pdo); // 接続を閉じる $pdo = null; ?>
これを実行すると以下の様に表示されます。「id」が「1」~「3」の「price」が1.1倍になったのがわかります。
C:\xampp\htdocs\_test>php pdo10.php id:1 name :パソコン001 price:100000 id:2 name :パソコン002 price:202000 id:3 name :パソコン003 price:303000 id:4 name :プリンタ001 price:50000 id:5 name :プリンタ002 price:150000 id:6 name :プリンタ003 price:60000 id:7 name :マウス001 price:3000 id:8 name :マウス002 price:5000 id:9 name :マウス003 price:7000 id:1 name :パソコン001 price:110000 id:2 name :パソコン002 price:222200 id:3 name :パソコン003 price:333300 id:4 name :プリンタ001 price:50000 id:5 name :プリンタ002 price:150000 id:6 name :プリンタ003 price:60000 id:7 name :マウス001 price:3000 id:8 name :マウス002 price:5000 id:9 name :マウス003 price:7000
■テーブルレコード削除(DELETE)の例
prepare メソッドで削除SQLを準備し bindValue メソッドを使って名前付パラメータに値を設定後、 execute メソッドで削除の実行を行います。
<?php ob_start(function($buf){ return mb_convert_encoding($buf, 'SJIS', 'UTF-8'); }); // MySQLデータベースに接続 $dsn = "mysql:host=localhost;dbname=pdo;"; $user = 'root'; $password = 'password'; try { // PDOクラス生成(データベース接続) $pdo = new PDO($dsn, $user, $password); } catch (PDOException $e) { // エラー発生 die('データベース接続ERROR:'.$e->getMessage()."\n"); } // === 全データの取得・表示 === function dispAll($_pdo) { $sql = "select * from `tm_shohin` order by id"; // 全データ取得SQL $pdostmt = $_pdo->prepare($sql); // SELECTクエリの準備 $pdostmt->execute(); // SELECTクエリの実行 while ($result = $pdostmt->fetch()) { echo "id:".$result["id"]." name :".$result["name"]." price:".$result["price"]."\n"; } echo "\n"; } // 削除前の表示 dispAll($pdo); // レコード削除(UPDATE)SQL $sql = "delete from `tm_shohin` where id between :id1 and :id2"; // SQL文の準備 $pdostmt = $pdo->prepare($sql); // データ変数設定 $intId1 = 7; $intId2 = 9; // データバインド $pdostmt->bindValue(":id1", $intId1, PDO::PARAM_INT); $pdostmt->bindValue(":id2", $intId2, PDO::PARAM_INT); // SQL文の実行 $ret = $pdostmt->execute(); // 削除後の表示 dispAll($pdo); // 接続を閉じる $pdo = null; ?>
これを実行すると以下の様に表示されます。「id 」の「7」~「9」のレコードが削除されたのがわかります。
C:\xampp\htdocs\_test>php pdo11.php id:1 name :パソコン001 price:110000 id:2 name :パソコン002 price:222200 id:3 name :パソコン003 price:333300 id:4 name :プリンタ001 price:50000 id:5 name :プリンタ002 price:150000 id:6 name :プリンタ003 price:60000 id:7 name :マウス001 price:3000 id:8 name :マウス002 price:5000 id:9 name :マウス003 price:7000 id:1 name :パソコン001 price:110000 id:2 name :パソコン002 price:222200 id:3 name :パソコン003 price:333300 id:4 name :プリンタ001 price:50000 id:5 name :プリンタ002 price:150000 id:6 name :プリンタ003 price:60000