SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

PEARライブラリ活用

PEAR MDB2でPHPからデータベースを操作する

PEARライブラリ活用 (4)

  • X ポスト
  • このエントリーをはてなブックマークに追加

トランザクション

 データベースの処理のひとまとまりをトランザクションといいます。ひとまとまりの処理は、最初から最後まで、すべてが正しく実行されなければなりません。もし、途中でエラー等の異常事態が発生したら、それまでのすべての処理をなかったことにしなければなりません。

 MySQLのInnoDBはトランザクションをサポートしています。MDB2もそのためのメソッドを実装しているので、実行して試してみましょう。

$db->beginTransaction();
$db->exec('DELETE FROM books');
$db->rollback();
//$db->commit();

 beginTransactionでトランザクションが開始されます。2行目ですべてのデータを削除していますが、3行目のrollbackによって、トランザクション開始以後の操作がすべてキャンセルされます。rollbackの代わりにcommitと書けば、変更が確定し、元には戻せなくなります。

 これは簡単な例ですが、実際にトランザクションを利用する場面では、「結果の整合性をチェックして、エラーがあればrollbackし、問題なければcommit」という具合に実装します。

SELECT結果の処理

 SELECT文の実行にはqueryメソッドを使います。

$rs = $db->query('SELECT * FROM books');

 実行結果は次のように1行ずつ取り出して処理することができます。

echo '<ul>';
while($row = $rs->fetchRow()){
    echo '<li>';
    echo print_r($row);
    echo '</li>';
}
echo '</ul>';

 次のような結果になります。print_r関数でこれは配列の中身を表示しています。$row[1]とすればタイトルだけ、$row[2]とすれば出版社だけを取り出せます。

  • Array ( [0] => 1 [1] => The Art of Computer Programming 1 [2] => アスキー [3] => 2004 [4] => 10290 ) 1
  • Array ( [0] => 2 [1] => フリーソフトウェアと自由な社会 [2] => アスキー [3] => 2003 [4] => 3360 ) 1-
  • Array ( [0] => 3 [1] => 計算機プログラムの構造と解釈 [2] => ピアソンエデュケーション [3] => 2000 [4] => 4830 ) 1-
  • Array ( [0] => 4 [1] => プログラミング作法 [2] => アスキー [3] => 2000 [4] => 2940 ) 1-
  • Array ( [0] => 5 [1] => Webアプリケーション構築入門 [2] => 森北出版 [3] => 2007 [4] => 3360 ) 1-
  • Array ( [0] => 6 [1] => プログラミングPHP [2] => O'Reilly [3] => 0 [4] => 0 ) 1-
  • Array ( [0] => 7 [1] => [2] => O'%Reilly [3] => 2008 [4] => 1995 ) 1-
  • Array ( [0] => 8 [1] => 初めてのPHP [2] => O'Reilly [3] => 0 [4] => 0 ) 1-
  • Array ( [0] => 9 [1] => '初めてのPHP' [2] => 'O\'Reilly' [3] => 0 [4] => 0 ) 1-

 fetchRow()fetchRow(MDB2_FETCHMODE_ORDERED)と同じで、結果の1行をふつうの配列で取り出します。MDB2_FETCHMODE_ASSOCとすれば連想配列、MDB2_FETCHMODE_OBJECTとすればオブジェクトとして取り出せます。連想配列として取り出したときは$row['title']、オブジェクトとして取り出したときは$row->titleのようにして、個々のデータを取得できます。

ワイルドカード処理

 この項は少し細かい話なので、初めて読むときはとばしてもかまいません。

 この時点で、テーブルbooksの内容は次のようになっています。

テーブルbooksの内容
idtitlepublisheryearprice
1The Art of Computer Programming 1アスキー200410290
2フリーソフトウェアと自由な社会アスキー20033360
3計算機プログラムの構造と解釈ピアソンエデュケーション20004830
4プログラミング作法アスキー20002940
5Webアプリケーション構築入門森北出版20073360
6プログラミングPHPO'Reilly00
7O'%Reilly20081995
8初めてのPHPO'Reilly00
9'初めてのPHP''O\'Reilly'00

 このテーブルから、「O'%」から始まるpublisherの値を取り出すことを考えましょう。SELECT文でLIKE節を使うのですが、「%」があるため、少し難しくなります(「%」は任意の文字列にマッチするワイルドカード。ちなみに、「_」は任意の1文字にマッチ)。

 単純なプリペアードステートメントではうまくいきません。「O'%」の「%」がワイルドカードとして処理されてしまうからです。

mdb2-2.php
$stmt=$db->prepare('SELECT publisher,year FROM books WHERE publisher LIKE ?');
$rs=$stmt->execute(array($keyword.'%'));
echo '<ul>';
while($row = $rs->fetchRow()) echo "<li>$row[0]</li>";
echo '</ul>';

 ほしい結果(つまり「O'%Reilly」)以外のものも取得してしまっています。

O'Reilly
O'%Reilly
O'Reilly

 次のように書くのが正解です。

$sql="SELECT publisher,year FROM books WHERE publisher LIKE 'O\'\%%'";
$rs=$db->query($sql);
echo '<ul>';
while($row = $rs->fetchRow()) echo "<li>$row[0]</li>";
echo '</ul>';

 正しい結果になります。

O'%Reilly

 しかし、SELECT文を手で書くわけにはいきません。「'」を「\'」にする処理も自動で行わなければなりません。先に紹介したquoteメソッドは、結果を「'」で囲んでしまうので、ここでは使えません。その代わりに、escapeメソッドを使います。

$sql=("SELECT publisher,year FROM books ".
  "WHERE publisher LIKE '{$db->escape($keyword,true)}%'");
echo "<p>$sql</p>";
$rs=$db->query($sql);
echo '<ul>';
while($row = $rs->fetchRow()) echo "<li>$row[0]</li>";
echo '</ul>';

 quoteescapeの違いは次の通りです。

  • quoteはSQL文で直接使えない文字を使えるように変換し、全体を「'」で囲む(例:quote("O'Reilly")の結果は"'O\'Reilly'")
  • escapequoteと同様だが、全体を「'」で囲まない(例:escape("O'Reilly")の結果は"O\'Reilly")。また、2番目の引数をtrueにすると、ワイルドカード文字(「%」と「_」)の前にバックスラッシュが付く。その結果、これらの文字がワイルドカード文字とは見なされなくなり、ここでの目的が達成される。

 quoteの場合と同様で、escapeをプリペアードステートメントで使うことはできません。次のように書いても失敗します(結果無し)。

$stmt=$db->prepare('SELECT publisher,year FROM books WHERE publisher LIKE ?');
$rs=$stmt->execute(array($db->escape($keyword,true)));
echo '<ul>';
while($row = $rs->fetchRow()) echo "<li>$row[0]</li>";
echo '</ul>';

 どうしてもプリペアードステートメントを使いたいなら、「%」と「_」は別に処理しなければなりません。

$stmt=$db->prepare('SELECT publisher,year FROM books WHERE publisher LIKE ?');
$rs=$stmt->execute(array(strtr($keyword,array('%'=>'\%','_'=>'\_')).'%'));
echo '<ul>';
while($row = $rs->fetchRow()) echo "<li>$row[0]</li>";
echo '</ul>';

 「プリペアードステートメントを使うのが基本」だと先に述べましたが、ここで見たように、プリペアードステートメントだけでは完璧にはならないのです。

次のページ
PEAR MDB2以外の方法

この記事は参考になりましたか?

  • X ポスト
  • このエントリーをはてなブックマークに追加
PEARライブラリ活用連載記事一覧

もっと読む

この記事の著者

山田 祥寛(ヤマダ ヨシヒロ)

静岡県榛原町生まれ。一橋大学経済学部卒業後、NECにてシステム企画業務に携わるが、2003年4月に念願かなってフリーライターに転身。Microsoft MVP for Visual Studio and Development Technologies。執筆コミュニティ「WINGSプロジェクト」代表。主な著書に「独習シリーズ(Java・C#・Python・PHP・Ruby・JSP&サーブレットなど)」「速習シリーズ(ASP.NET Core・Vue.js・React・TypeScript・ECMAScript、Laravelなど)」「改訂3版JavaScript本格入門」「これからはじめるReact実践入門」「はじめてのAndroidアプリ開発 Kotlin編 」他、著書多数

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

WINGSプロジェクト 矢吹 太朗(ヤブキ タロウ)

WINGSプロジェクトについて>有限会社 WINGSプロジェクトが運営する、テクニカル執筆コミュニティ(代表 山田祥寛)。主にWeb開発分野の書籍/記事執筆、翻訳、講演等を幅広く手がける。2018年11月時点での登録メンバは55名で、現在も執筆メンバを募集中。興味のある方は、どしどし応募頂きたい。著書記事多数。 RSS X: @WingsPro_info(公式)、@WingsPro_info/wings(メンバーリスト) Facebook

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

  • X ポスト
  • このエントリーをはてなブックマークに追加
CodeZine(コードジン)
https://codezine.jp/article/detail/2480 2008/05/26 14:00

おすすめ

アクセスランキング

アクセスランキング

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー

アクセスランキング

アクセスランキング