データ|データベース
一度書いたらどこでも実行
一度書いたらどこでも実行
これは Java のマーケティング スローガンですが、PHP の重要な機能の 1 つでもあります。多くのビジネス モデルは、製品を幅広い顧客ベースに販売できるようにするために、オペレーティング システムの独立性に依存しています。では、なぜ特定のデータベース ベンダーと結びつくのでしょうか?データベース抽象化レイヤーを使用すると、データベースから独立してアプリケーションを開発できます。ただし、多くの場合、これらは期待以上にパフォーマンスに影響を及ぼしたり、データベース固有のコードをすべて削除できるほど抽象的ではありません。
この記事は何を教えてくれますか?
この記事では、データベース抽象化パッケージ PEAR MDB について詳しく説明します。この記事の焦点は、データ型の抽象化や XML ベースのスキーマ管理など、同様のパッケージで提供される機能を超える MDB のより高度な機能にあります。 PHP と SQL の基本的な理解を推奨します。
なぜ別のデータベースクラスが必要なのでしょうか?
通常、Web プロジェクトは、顧客が使用する RDBMS (リレーショナル データベース管理システム) を決定した後、既存の IT インフラストラクチャに追加されます。予算の違いによって、展開するデータの選択に影響が出る可能性があるため、そうではありません。結局のところ、開発者としては、特定のベンダーに縛られたくないだけかもしれません。それ以来、サポートされている各データのバージョンを維持するか、より多くのパフォーマンスを犠牲にして必要以上に使いやすさを向上させることを意味します。PEAR MDB を導入してください。
MDB は、RDBMS に依存しない PHP プログラムの作成を簡単なプロセスにすることに重点を置いたデータベース抽象化レイヤーです。 PHP の他のいわゆるデータベース抽象化レイヤーのほとんどは、サポートされているすべてのデータベースと非常に限定された抽象化 (主にシーケンスのみ) に共通の API を提供します。一方、MDB を使用すると、データベースによって送受信されるすべてのデータを抽象化できます。データベース スキーマも RDBMS に依存しない形式で定義できます。ただし、高いパフォーマンスと使いやすさを維持しながら、これらの機能を提供します。これは、2 つの一般的なデータベース抽象化レイヤー、PEAR DB と Metabase を詳しく調べ、それらを統合することによって実現されました。そして、統合プロセス中に、この機会を利用して、統合された API とパフォーマンスに影響を与える設計をクリーンアップしました。
MDBはどのようにして登場しましたか?
2001 年の秋に遡ると、私は会社のプログラミング フレームワーク RDBMS を独立させることができるデータベース抽象化パッケージを探していました。目標は、データベース固有のコードの量をゼロに減らすことです。このような機能を提供する唯一のパッケージは Metabase です。ただし、Metabase の一部には、PHP3 との互換性を保つために不快な API が含まれています。それにもかかわらず、私たちは Metabase が唯一の選択肢であると判断しました。しかし、Metabase にパフォーマンス改善パッチを追加した後でも、パフォーマンスを犠牲にしすぎていると感じていました。私たちは 2001 年の PHP 国際会議で Metabase の作者たちと会い、Metabase のようなものを PEAR プロジェクトの一部にすることの利点について話し合いました。その後間もなく、PEAR DB とメタベースを統合することで考えられる利点について、PEAR メーリング リストで別の議論が始まりました。社内で何度も議論を重ねた結果、この仕事を引き受けることにしました。数か月にわたる懸命な作業を経て、MDB の最初の安定版リリースが完成しました。
MDB は何を提供しますか?
MDB は、PEAR DB とメタベースのほとんどの機能を組み合わせています。実際、現在存在しない PEAR DB の唯一の機能は、結果セットとしてオブジェクトを返すことです。この機能は一般的に使用されておらず、パフォーマンス上のペナルティが非常に明らかであるため、この機能は削除されました。 API をできる限り使いやすくするために、多くの開発時間が費やされています。最終的に、MDB はこれらの機能を非常に高度に提供し、少なくとも PEAR DB と同じくらい高速で、Metabase よりも大幅に高速です。これらの最も重要な機能のリスト:
OO スタイル API
事前に準備されたクエリ シミュレーション
データベースに出入りするすべてのデータの完全なデータ型抽象化 (LOB サポートを含む)
トランザクション サポート
データベース/テーブル /インデックス/シーケンスの作成/discard/change
RDBMS に依存しないデータベース スキーマ管理
PEAR フレームワークに継承 (PEAR インストーラー、PEAR エラー処理など)
それでは、どのように使用するのでしょうか?
MDB は、非常に高度な抽象化機能をいくつか提供します。これらの機能はオプションのみであることを覚えておくことが重要です。ただし、RDBMS に依存しない PHP プログラムを作成する場合は、これらを使用することが非常に重要です。 MDB の使用がいかに簡単であるかを示す例は、この記事の最後にある「リンクとドキュメント」セクションにあります。前述したように、この記事の焦点は、MDB を他の PHP データベース抽象化レイヤーと区別する機能を紹介することです。これらすべてのサンプル スクリプトのコードは、この記事に同梱されている CD に収録されています。
ただし、その前に MDB をインストールする必要があります。これは実際には、PEAR インストーラーを使用すると非常に簡単です。この記事では PEAR インストーラーについて完全に説明することはできませんが、次号では PEAR フレームワークの詳細について詳しく説明する予定だと聞いています。インストーラーを Windows 上で実行できるようにする作業が進行中ですが、サポートはまだ少し不安定です。 *nix システムの場合、システムに CGI バージョンの PHP をインストールする必要があり、次のコマンドを実行するだけです:
lynx -source go-pear.org|php
インストールが完了したら、あと 1 つ入力するだけです。コマンド行 これですべて完了です。
pear install MDB
前のプロセスがうまくいかない場合は、PEAR MDB ホームページからパッケージを直接入手するオプションが常にあります。 URLは記事末尾に記載しております。
データ型の抽象化を使用する
ほとんどのデータベースには何らかの個性や癖がある傾向があるため、MDB にとってこれらの違いを開発者から隠すことは非常に重要です。 MDB は、独自の内部データ型 (テキスト、ブール、整数、10 進数、浮動小数点、日付、時刻、タイムスタンプ、ラージ オブジェクト (ファイル)) を定義することでこれを実現します。データベースとの間でやり取りされるすべてのデータは、MDB の内部形式との間で変換できます。このセクションに関連するサンプル スクリプトは、datatype ディレクトリにあります。次のクエリを見てみましょう:
$session = '098f6bcd4621d373cade4e832627b4f6'; $query = 'SELECT createtime, user_id FROM session';
$query .= ' WHERE session = '.$session;
$query .= ' AND lastaccess < '.$timeout;
このクエリがデータベースに送信された場合、失敗する可能性があります。その理由は、$name に格納されている値を正しい文字列形式に変換する必要があるためです。これは、$name の内容に特殊なエスケープ文字が含まれているか、引用符で囲まれている可能性があることを意味している可能性があります。 PEAR DB は、この目的のためにメソッド DB:.quote() を提供します。 MDB では、このメソッドは MDB::getTextValue() と呼ばれます。違いは、MDB が前にリストした各データ型に対してそのような関数を提供していることです。したがって、$timeout を正しい形式に変換することもできます。
// $timeout を MDB タイムスタンプ形式に変換します
$timeout = MDB_date::unix2Mdbstamp($timeout);
// データ型変換の仕組みを示す SELECT クエリ
$query = 'SELECT createtime, user_id FROM session';
$query .= ' WHERE session = '.$mdb->getTextValue($session);
$query .= ' AND lastaccess < '.$mdb->getTimestampValue($timeout);
例として、最初の行のみを取得したいと仮定します。 MDB::queryRow() は最初の行を取得し、結果セットを解放してその内容を返します。これはまさに私たちが望んでいることです。
$result = $mdb->queryRow($query);
しかし、RDBMS が異なれば、日付などのデータを返すために使用する形式も異なります。したがって、何らかのデータに対して計算を実行する場合は、選択した RDBMS に関係なく、同じ形式でデータを返すことが重要です。これは、MDB によって半自動的に実行できます。必要なのは、結果の列がどの型になるかを指定することだけで、MDB が変換を処理します。最も簡単な方法は、そのような情報をクエリ関数に渡すことです。
$types = array('timestamp', 'integer');
$result = $mdb->queryRow($query, $types);
これは、結果セットの最初の列の型が次であることを MDB に伝えます。 'timestamp '、2 番目の列は 'integer' です。すべてのクエリ関数は、このようなメタ情報をオプションのパラメーターとして受け入れることができます。 MDB::setResultTypes() を使用して、後からデータを設定することもできます。データの取得元のデータベースに応じて、データはそれに応じて変換されてデータが返されます。 MDB 内のタイムスタンプのデータ形式は ISO 8601 標準に従います。 PEAR::Date などの他のパッケージはこの形式を処理できます。 MDB は、MDB_Date クラスでいくつかのデータ形式変換関数も提供しており、これをオプションで含めることができます。
多くの RDBMS は同様に整数データを返すため、整数データを変換する必要はありません。したがって、パフォーマンスをわずかに向上させるには、次のようにすることができます:
$types = array('timestamp');
$result = $mdb->queryRow($query, $types);
この方法は次のとおりです。結果セットの最初の列のみが変換されます。もちろん、MDB を使用してさまざまなデータベースから整数を返す場合、これが問題になる可能性があります。ただし、わずかなパフォーマンスの向上はリスクに見合う価値がない可能性があります。しかし、繰り返しになりますが、これらの機能の使用はオプションにすぎないことがわかります。
リスト 1 は、準備されたクエリの使用例を示しています。これは、データがデータベースに渡されることが唯一の違いであるが、クエリの構造は同じである多数のクエリを実行する必要がある場合に非常に便利です。高度なデータベースでは、解析されたクエリをメモリに保存してパフォーマンスを向上させることができます。
リスト 1
$alldata = array(
array(1, 'one', 'un'),
array(2, 'two', 'deux'),
array(3, 'three', 'trois '),
array(4, 'four', 'quatre')
);
$p_query = $mdb->prepareQuery('INSERT INTO数値VALUES (?,?,?)');
$param_types = array('integer', 'text', 'text');
foreach ($alldata as $row) {
$mdb->execute($p_query, NULL, $row, $param_types);
}
$alldata に格納されている 4 つの配列はすべて、execute ステートメントで使用されます。データは自動的に正しい形式に変換されます。これは挿入ステートメントであるため、データ型を設定する必要がある結果列がないため、MDB::execute() の 2 番目のパラメーターは NULL に設定されます。
サポートされているデータ型の中には、データベースにファイルを保存できる LOB (ラージ オブジェクト) があります。バイナリ ファイルは BLOB (バイナリ ラージ オブジェクト) に格納され、通常のテキスト ファイルは CLOB (キャラクタ ラージ オブジェクト) に格納されます。 MDB では、準備された INSERT クエリと UPDATE クエリを使用してのみ LOB を格納できます。 MDBA::setParamBlob() または MDB::setParamClob() を使用して、準備済みクエリ内の LOB フィールドの値を設定できます。どちらの関数も、MDB::createLob() を使用して作成できる LOB オブジェクトが渡されることを想定しています。
$binary_lob = array(
'Type' => 'inputfile',
'FileName' => './myfile.gif'
);
$blob = $mdb->createLob($binary_lob);
$character_lob = array(
'Type' => 'data',
'Data' => 'これは CLOB データの非常に長い文字列コンテナになります'
);
$clob = $mdb-> createLob($character_lob);
ご覧のとおり、MDB::createLob() にはリレーショナル配列が渡されます。 Type キーの値は、data、inputfile、outputfile のいずれかになります。最初の 2 つは、LOB をデータベースに書き込む場合に使用されます。 LOB が変数に格納されている場合は、inputfile を使用する必要があるときにファイルから LOB を直接読み取る必要があります。最後に、データベースから LOB を読み取る場合は、outpufile を使用する必要があります。 data と inputfile のどちらを使用しているかに応じて、上記の例のように、Filename キーまたは Data キーの値を指定する必要があります。ここで、以前の LOB をデータベースに保存します。
$p_query = $mdb->prepareQuery('INSERT INTO files (id, b_data, c_data) VALUES (1, ?, ?)');
$mdb->setParamBlob($p_query, 1 , $blob , 'b_data');
$mdb->setParamClob($p_query, 2 , $clob, 'c_data');
$result = $mdb->executeQuery($p_query);
を取得するにはデータベースからのデータ 上記のファイルを取得するには、まずデータベースからデータを選択し、MDB::createLob() を使用して LOB オブジェクトを作成する必要があります。今回は「Type」を「outputfile」に設定します
$mdb->query('SELECT b_data FROM files WHERE id = 1');
$binary_lob = array(
'Type' => 'outputfile' './ myfile2.gif'
);
$blob = $mdb->createLob($binary_lob);
これで、MDB::readLob() を使用して結果セットから LOB を読み取ることができるようになりました。 MDB::readLob() に長さ 0 を渡すことは、LOB 全体が読み取られ、前に指定したファイルに保存されることを意味します。タスクが完了したら、リソースを解放できます。ゼロより大きい任意の長さを設定し、while ループを使用して MDB::endofLob() をチェックして LOB を読み取ることもできます。
$mdb->readLob($blob, $data, 0);
これはほとんどの PHP で機能するため、このフェッチ関数を MDB::fetchAll() のような一括フェッチ関数と混同しないように注意してください。データベースの拡張時に問題が発生します。場合によっては、MDB は一括取得関数を使用して LOB を取得できる場合があります。
このセクションで説明したように、MDB 機能自体のネイティブ データ型のセットは、データベース内のネイティブ データ型に自動的にマッピングされます。これにより、データベースとの間でどのようなデータを送受信しても、使用する RDBMS に関係なく同じ形式になることが保証されます。このセクションの冒頭ですでに述べたように、これには明らかに、データベースが MDB が予期するデータ型を使用する必要があります。この必要性は、マッピングのコストを確実に小さくするために使用されます。次のセクションでは、データベース内で正しいデータ型の使用を MDB がどのように支援するかを説明します。
XML スキーマ ファイルの使用
前の段落で説明した機能を使用すると、真にデータベースに依存しないプログラムを作成できます。しかし、MDB はさらに一歩進んで、XML でスキーマを定義できるようにします。マネージャーは、このスキーマを各 RDBMS に必要な SQL ステートメントに変換します。これは、サポートされているすべての RDBMS で同じスキーマを使用できることを意味します。このセクションの例は、xml_schema ディレクトリにあります。
XML スキーマ ファイルを最初から作成します。まず、XML ドキュメントを定義する必要があります。データベース定義はデータベース タグに含まれます。データベースの名前は、name タグを使用して定義されます。 create タグは、データベースが存在しない場合にデータベースを作成する必要があるかどうかをマネージャーに伝えます。スキーマ ファイルを複数のファイルに分割する場合は、最初にマネージャーに送信するファイルで create を 1 に設定します。
おそらく、データベース名 auth から、このデータベースの目的は、簡単な認証手順のためのユーザー データを保存することであると推測できます。リスト 2 は、ユーザー データを保存できるテーブルを定義します。
リスト 2