mirror of
https://github.com/yiisoft/yii.git
synced 2026-03-12 02:56:55 +01:00
227 lines
13 KiB
Plaintext
227 lines
13 KiB
Plaintext
データアクセスオブジェクト (DAO)
|
|
=========================
|
|
|
|
データアクセスオブジェクト (DAO) は、異なるデータベース管理システム (DBMS) 上に保存されたデータに接続するための包括的な API を提供します。
|
|
DAO を用いてデータにアクセスすることで、コードを変更せずに異なる DBMS を利用する事が可能になります
|
|
|
|
Yii DAO は MySQL や PostgreSQL といった多くのポピュラーな DBMS への統一的なデータアクセスを提供する [PHP Data Objects (PDO)](http://php.net/manual/en/book.pdo.php) 拡張を用いて構築されています。
|
|
そのため、Yii DAO を利用するには、PDO 拡張と特定の PDO データベースドライバ (たとえば `PDO_MYSQL`) がインストールされている必要があります。
|
|
|
|
Yii DAO は、主に以下の 4 つのクラスから構成されています:
|
|
|
|
- [CDbConnection]: データベースとの接続を表します。
|
|
- [CDbCommand]: データベースに対して実行する SQL 文を表します。
|
|
- [CDbDataReader]: クエリ結果セットからの後戻りしないストリームを表します。
|
|
- [CDbTransaction]: DB トランザクションを表します。
|
|
|
|
以下に、さまざまなシナリオでの Yii DAO の使用方法を紹介します。
|
|
|
|
データベース接続の確立
|
|
--------------------------------
|
|
|
|
データベース接続を確立させるには、[CDbConnection] のインスタンスを作成して active にします。
|
|
データソース名 (DSN) がデータベースに接続するために要求される情報を指定するために必要です。
|
|
おそらく username と password も接続を確立させるために必要でしょう。
|
|
接続を確立する際にエラーが起こると例外が発生します (たとえば、間違った DSN や無効な username/password)。
|
|
|
|
~~~
|
|
[php]
|
|
$connection=new CDbConnection($dsn,$username,$password);
|
|
// 接続を確立する。try...catch で例外処理を行う事もできます
|
|
$connection->active=true;
|
|
......
|
|
$connection->active=false; // 接続を閉じる
|
|
~~~
|
|
|
|
DSN のフォーマットは、使用する PDO データベースドライバに依存します。
|
|
一般的には、DSN はその PDO ドライバ名に続けてコロン、その後に、ドライバ個別の接続シンタックスを指定します。
|
|
詳細な情報は、[PDO documentation](http://www.php.net/manual/en/pdo.construct.php) を参照してください。
|
|
以下に、一般に用いられる DSN フォーマットのリストを示します:
|
|
|
|
- SQLite: `sqlite:/path/to/dbfile`
|
|
- MySQL: `mysql:host=localhost;dbname=testdb`
|
|
- PostgreSQL: `pgsql:host=localhost;port=5432;dbname=testdb`
|
|
- SQL Server: `mssql:host=localhost;dbname=testdb`
|
|
- Oracle: `oci:dbname=//localhost:1521/testdb`
|
|
|
|
[CDbConnection] は [CApplicationComponent] から拡張されているため、[アプリケーションコンポーネント](/doc/guide/basics.application#sec-4) として使用できます。
|
|
そうするには、[アプリケーション初期構成](/doc/guide/basics.application#sec-2) 内で `db` という名前 (もしくは他の名前) のアプリケーションコンポーネントを下記のように設定します。
|
|
|
|
~~~
|
|
[php]
|
|
array(
|
|
......
|
|
'components'=>array(
|
|
......
|
|
'db'=>array(
|
|
'class'=>'CDbConnection',
|
|
'connectionString'=>'mysql:host=localhost;dbname=testdb',
|
|
'username'=>'root',
|
|
'password'=>'password',
|
|
'emulatePrepare'=>true, // MySQL の設定によっては必要
|
|
),
|
|
),
|
|
)
|
|
~~~
|
|
|
|
その後、[CDbConnection::autoConnect] 設定が false になっていない限り、すでに自動的にアクティブになっている `Yii::app()->db` を利用してDB 接続にアクセスできます。
|
|
このアプローチを使うと、単一の DB 接続をコード中の色々な場所で共有することができます。
|
|
|
|
SQL 文の実行
|
|
------------------------
|
|
|
|
一度データベース接続を確立すれば、[CDbCommand] を使用して SQL 文を実行できます。
|
|
まず、特定の SQL 文によって [CDbConnection::createCommand()] を呼び、[CDbCommand] のインスタンスを作成します:
|
|
|
|
~~~
|
|
[php]
|
|
$connection=Yii::app()->db; // "db" 接続を構成したと仮定した場合
|
|
// もしくは、明示的に接続を作成してもよい
|
|
// $connection=new CDbConnection($dsn,$username,$password);
|
|
$command=$connection->createCommand($sql);
|
|
// もし必要なら、SQL 文を下記のように更新できます:
|
|
// $command->text=$newSQL;
|
|
~~~
|
|
|
|
SQL 文は、次の2つの方法のうちのいずれかで、[CDbCommand] によって実行されます:
|
|
|
|
- [execute()|CDbCommand::execute]: `INSERT`, `UPDATE`, `DELETE` のような、非クエリ型の SQL 文を実行します。
|
|
成功した場合、SQL 文の実行によって影響された行数を返します。
|
|
|
|
- [query()|CDbCommand::query]: `SELECT` のような、データ行を返す SQL 文を実行します。
|
|
成功した場合、結果の行を読み出すことが出来る [CDbDataReader] インタンスが返されます。
|
|
便宜上、直接クエリ結果の行を返す一連の `queryXXX()` メソッドも実装されています。
|
|
|
|
SQL 文の実行中にエラーが発生した場合は、例外が発生します。
|
|
|
|
~~~
|
|
[php]
|
|
$rowCount=$command->execute(); // 非クエリ型 SQL を実行する
|
|
$dataReader=$command->query(); // クエリ型 SQL を実行する
|
|
$rows=$command->queryAll(); // クエリを実行して、結果の全行を返す
|
|
$row=$command->queryRow(); // クエリを実行して、結果の最初の行を返す
|
|
$column=$command->queryColumn(); // クエリを実行して、結果の最初の列を返す
|
|
$value=$command->queryScalar(); // クエリを実行して、最初の行の最初の項目を返す
|
|
~~~
|
|
|
|
クエリ結果の取得
|
|
----------------------
|
|
|
|
[CDbCommand::query()] により [CDbDataReader] インスタンスを生成した後に、[CDbDataReader::read()] を繰り返し呼ぶことで、結果データの行を取り出せます。
|
|
データを一行ずつ取り出すために、PHP の `foreach` 文の中で [CDbDataReader] を使用できます。
|
|
|
|
~~~
|
|
[php]
|
|
$dataReader=$command->query();
|
|
// false が返るまで、繰り返し read() を呼び出します
|
|
while(($row=$dataReader->read())!==false) { ... }
|
|
// foreach を用いてデータの全行を取り出します
|
|
foreach($dataReader as $row) { ... }
|
|
// 一つの配列として、一回で全行を取り出します
|
|
$rows=$dataReader->readAll();
|
|
~~~
|
|
|
|
> Note|注意: [query()|CDbCommand::query] と異なり、全ての `queryXXX()` メソッドは直接データを返します。
|
|
たとえば、[queryRow()|CDbCommand::queryRow] は、クエリ結果の最初の行を表現する配列を返します。
|
|
|
|
トランザクションの使用
|
|
------------------
|
|
|
|
アプリケーションがいくつかのクエリを実行して、各クエリがデータベース中の情報を読み書きする場合は、クエリのどれかが実行されずに残る、という事が無いように確認することが重要です。
|
|
Yii の [CDbTransaction] インスタンスとして表されるトランザクションは、このような場合に開始できます:
|
|
|
|
- トランザクションを開始する。
|
|
- 一つずつクエリを実行する。データベースへのどんな更新も外の世界には見えません。
|
|
- トランザクションをコミットする。処理が成功した場合、更新が適用されます。
|
|
- もしクエリのひとつが失敗した場合、全処理がロールバックされます。
|
|
|
|
上記のワークフローは次のコードを使用して実装できます:
|
|
|
|
~~~
|
|
[php]
|
|
$transaction=$connection->beginTransaction();
|
|
try
|
|
{
|
|
$connection->createCommand($sql1)->execute();
|
|
$connection->createCommand($sql2)->execute();
|
|
//.... 他の SQL の実行
|
|
$transaction->commit();
|
|
}
|
|
catch(Exception $e) // クエリの実行に失敗した場合、例外が発生します
|
|
{
|
|
$transaction->rollback();
|
|
}
|
|
~~~
|
|
|
|
パラメータのバインディング
|
|
------------------
|
|
|
|
[SQL インジェクション攻撃](http://ja.wikipedia.org/wiki/SQL%E3%82%A4%E3%83%B3%E3%82%B8%E3%82%A7%E3%82%AF%E3%82%B7%E3%83%A7%E3%83%B3) を避け、繰り返し使用される SQL 文の実行パフォーマンスを改善するために、SQL 文とオプションのパラメータプレースホルダを "準備 prepare" することが出来ます。
|
|
プレースホルダは、パラメータバインディングの過程で、実引数と置き換えられることになっています。
|
|
|
|
パラメータプレースホルダは、名前付き (ユニークなトークンとして表される) か、無名 (クエスチョンマークとして表わされる) かのどちらかを使えます。
|
|
[CDbCommand::bindParam()] か [CDbCommand::bindValue()] を呼び出す事で、これらのプレースホルダを実引数に置き換えます。
|
|
パラメータを引用符で囲む必要はありません。下層のデータベースドライバがその処理を行なってくれます。
|
|
パラメータバインディングは、SQL 文を実行する前に行われなければなりません。
|
|
|
|
~~~
|
|
[php]
|
|
// ":username" と ":email" の二つのプレースホルダをもつ SQL
|
|
$sql="INSERT INTO tbl_user (username, email) VALUES(:username,:email)";
|
|
$command=$connection->createCommand($sql);
|
|
// プレースホルダ ":username" を実際の username 値で置き換える
|
|
$command->bindParam(":username",$username,PDO::PARAM_STR);
|
|
// プレースホルダ ":email" を実際の email 値で置き換える
|
|
$command->bindParam(":email",$email,PDO::PARAM_STR);
|
|
$command->execute();
|
|
// 別のパラメータを使って別の行を INSERT する
|
|
$command->bindParam(":username",$username2,PDO::PARAM_STR);
|
|
$command->bindParam(":email",$email2,PDO::PARAM_STR);
|
|
$command->execute();
|
|
~~~
|
|
[bindParam()|CDbCommand::bindParam] メソッドと [bindValue()|CDbCommand::bindValue] メソッドは、とても似ています。
|
|
唯一の違いは、前者はパラメータにバインドするのに PHP 変数の参照を使い、後者は変数の値を使うということです。
|
|
大きなメモリブロックで表わされるデータをパラメータに指定する場合は、パフォーマンス的に前者の方法を利用する事を推奨します。
|
|
|
|
バインディングパラメータについての詳細については、[関連する PHP ドキュメント](http://www.php.net/manual/ja/pdostatement.bindparam.php) を参照してください。
|
|
|
|
カラムのバインディング
|
|
---------------
|
|
|
|
クエリの結果を抽出 (フェッチ) する場合、カラムを PHP 変数にバインドすることで、一行抽出されるごとに、変数に最新のデータが自動的に入るようにする事ができます。
|
|
|
|
~~~
|
|
[php]
|
|
$sql="SELECT username, email FROM tbl_user";
|
|
$dataReader=$connection->createCommand($sql)->query();
|
|
// 第 1 のカラム (username) を $username 変数にバインドする
|
|
$dataReader->bindColumn(1,$username);
|
|
// 第 2 のカラム (email) を $email 変数にバインドする
|
|
$dataReader->bindColumn(2,$email);
|
|
while($dataReader->read()!==false)
|
|
{
|
|
// $username と $email には、現在の行の username と email の内容が入っています
|
|
}
|
|
~~~
|
|
|
|
テーブルプレフィックスを使う
|
|
------------------
|
|
|
|
Yii はテーブルプレフィックスの使用について、統合的なサポートを提供しています。
|
|
テーブルプレフィックスとは、現在接続されているデータベースのテーブル名の前に付加されている文字列を意味します。
|
|
たいていは、共有ホスティング環境において使われます。複数のアプリケーションが単一のデータベースを共有しつつ、お互いを区別するために違うテーブルプレフィックスを使うという形です。
|
|
例えば、あるアプリケーションは `tbl_` をプレフィックスとして使い、他のアプリケーションは `yii_` を使うという具合です。
|
|
|
|
テーブルプレフィックスを使うためには、[CDbConnection::tablePrefix] プロパティを望みのテーブルプレフィックスに構成します。
|
|
そして、SQL 文においてテーブル名を指定するのに `{{TableName}}` という書式を使います。
|
|
ここで `TableName` はプレフィックスを除外したテーブル名を指します。
|
|
例えば、データベースが `tbl_user` という名前のテーブルを持っていて、`tbl_` がテーブルプレフィックスとして構成されている場合、ユーザに関するクエリのコードとして下記を使うことが出来ます。
|
|
|
|
~~~
|
|
[php]
|
|
$sql='SELECT * FROM {{user}}';
|
|
$users=$connection->createCommand($sql)->queryAll();
|
|
~~~
|
|
|
|
<div class="revision">$Id$</div>
|