Files
yii/docs/guide/de/database.dao.txt
2009-12-13 16:48:49 +00:00

274 lines
11 KiB
Plaintext

Data Access Objects (DAO)
=========================
Data Access Objects (Datenzugriffsobjekte, DAO) bieten eine allgemeine
API (Programmierschnittstelle) für den Zugriff auf Daten, die in unterschiedlichen
Datenbankmanagementsystemen (DBMS) gespeichert sind. Dadurch kann das zugrundeliegende DBMS ausgetauscht
werden ohne dass der Code, der DAO für den Zugriff auf die Daten nutzt, geändert
werden muss.
Yii-DAO setzt auf [PHP Data Objects (PDO)](http://php.net/manual/en/book.pdo.php)
auf. Das ist eine Erweiterung, die einen einheitlichen Datenzugriff auf viele,
weit verbreitete DBMS biete, wie z.B. MySQL und PostgreSQL. Um Yii-DAO nutzen
zu können, müssen daher die PDO-Erweiterung und die spezifischen PDO-Datenbanktreiber,
(z.B. `PDO_MYSQL`) installiert werden.
Yii-DAO besteht hauptsächlich aus den folgenden vier Klassen:
- [CDbConnection]: repräsentiert eine Verbindung zur Datenbank.
- [CDbCommand]: repräsentiert eine SQL-Anweisung, die gegenüber der Datenbank ausgeführt werden soll.
- [CDbDataReader]: repräsentiert einen forward-only (sinngem.:nur vorwärts
gerichteten) Datenstrom von Zeilen aus der Ergebnismenge einer Suchanfrage.
- [CDbTransaction]: repräsentiert eine DB Transaktion.
Nachfolgend zeigen wir den Einsatz von Yii-DAO in unterschiedlichen
Anwendungsfällen.
Aufbauen der Datenbankverbindung
--------------------------------
Um eine Verbindung zur Datenbank aufzubauen, müssen Sie eine [CDbConnection]-
Instanz erzeugen und aktivieren. Um die Anmeldeinformationen anzugeben, ist
ein Data Source Name (DSN) erforderlich. Benutzername und ein Passwort können ebenfalls
benötigt werden. Im Falle eines Fehlers (also ungültiger DSN oder falscher
Benutzername bzw. Passwort) während des Verbindungsaufbaus wird
eine Exception ausgelöst.
~~~
[php]
$connection=new CDbConnection($dsn,$username,$password);
// Verbindung aufbauen. Sie können mögliche Exceptions
// mit try...catch auffangen
$connection->active=true;
......
$connection->active=false; // Verbindung beenden
~~~
Das DSN-Format hängt vom benutzten PDO-Datenbanktreiber ab. Im Allgemeinen
enthält ein DSN den PDO-Treibernamen, gefolgt von einem Doppelpunkt, gefolgt
von der treiberspezifischen Verbindungssyntax. Siehe [PDO
Dokumentation](http://www.php.net/manual/en/pdo.construct.php) für weitere
Informationen. Nachfolgend eine Liste der gebräuchlichsten DSN-Formate:
- 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`
Da [CDbConnection] von [CApplicationComponent] abgeleitet ist, können wir sie auch
als [Applikationskomponente](/doc/guide/basics.application#application-component)
einsetzen. Dazu muss eine Anwendungskomponente `db` (die auch anderse benannt
sein kann) in der [Applikationskonfiguration](/doc/guide/basics.application#application-configuration)
wie folgt konfiguriert werden:
~~~
[php]
array(
......
'components'=>array(
......
'db'=>array(
'class'=>'CDbConnection',
'connectionString'=>'mysql:host=localhost;dbname=testdb',
'username'=>'root',
'password'=>'password',
'emulatePrepare'=>true, // wird von einigen MySQL-Installationen benötigt
),
),
)
~~~
Wir können dann auf die bereits automatisch aktivierte DB-Verbindung mittels
`Yii::app()->db` zugreifen, es sei denn, wir haben [CDbConnection::autoConnect]
mit false konfiguriert. Mit dieser Vorgehensweise kann eine einzelne
DB-Verbindung an vielen Stellen in unserm Code gemeinsam benutzt werden.
Ausführen von SQL-Anweisungen
-----------------------------
Nachdem eine Verbindung zur Datenbank aufgebaut ist, können mit [CDbCommand]
SQL-Anweisungen ausgeführt werden. Eine [CDbCommand]-Instanz wird erzeugt, indem
man [CDbConnection::createCommand()] mit der entsprechenden SQL-Anweisung
aufruft:
~~~
[php]
$command=$connection->createCommand($sql);
// falls erforderlich, kann die SQL Anweisung folgendermaßen aktualisiert werden:
// $command->text=$neuesSQL;
~~~
Eine SQL-Anweisung wird über [CDbCommand] auf eine der folgenden beiden Arten
ausgeführt:
- [execute()|CDbCommand::execute]: führt eine SQL-Anweisung aus, die keine
Abfrage ist, wie `INSERT`, `UPDATE` und `DELETE`. Bei Erfolg, liefert sie die Anzahl
der betroffenen Zeilen zurück.
- [query()|CDbCommand::query]: führt eine SQL-Abfrage wie `SELECT` aus, die
Datenzeilen zurückliefert. Falls erfolgreich, gibt sie eine [CDbDataReader]-Instanz
zurück, mit dem man die resultierenden Datenzeilen durchlaufen kann. Der Einfachheit
halber ist auch eine Reihe von `queryXXX()`-Methoden implementiert, die das Abfrageergebnis
direkt zurückliefern.
Falls ein Fehler während der Ausführung der SQL-Anweisung
auftritt, wird eine Exception ausgelöst,
~~~
[php]
$rowCount=$command->execute(); // führe die "Nicht-Abfrage"-SQL-Anweisung aus
$dataReader=$command->query(); // führe die SQL-Abfrage aus
$rows=$command->queryAll(); // Abfragen und Zurückgeben aller Zeilen des Ergebnisses
$row=$command->queryRow(); // Abfragen und Zurückgeben der ersten Zeile des Ergebnisses
$column=$command->queryColumn(); // Abfragen und Zurückgeben der ersten Spalte des Ergebnisses
$value=$command->queryScalar(); // Abfragen und Zurückgeben des ersten Feldes in der ersten Zeile
~~~
Arbeiten mit Query-Ergebnissen
------------------------------
Nachdem [CDbCommand::query()] eine Instanz von [CDbDataReader] erzeugt hat,
kann man, durch wiederholten Aufruf von [CDbDataReader::read()], Zeilen der
resultierenden Daten abfragen. Man kann [CDbDataReader] auch mit dem PHP
`foreach`-Konstrukt zum zeilenweise Abfragen nutzen.
~~~
[php]
$dataReader=$command->query();
// Wiederholter Aufruf von read() bis false zurückgegeben wird
while(($row=$dataReader->read())!==false) { ... }
// Mit foreach wird jede Datenzeile durchlaufen
foreach($dataReader as $row) { ... }
// Abfragen aller Zeilen auf einmal in ein einzelnes Array
$rows=$dataReader->readAll();
~~~
> Note|Hinweis: Anders als [query()|CDbCommand::query] liefern alle
`queryXXX()`-Methoden die Daten direkt zurück. Zum Beispiel gibt
[queryRow()|CDbCommand::queryRow] ein Array zurück, das die
erste Zeile des Abfrageergebnisses repräsentiert.
Verwenden von Transaktionen
---------------------------
Wenn eine Anwendung einige Abfragen ausführt, von denen jede Informationen
aus der Datenbank liest und/oder in sie schreibt, ist es wichtig, sicherzustellen,
dass in der Datenbank auch alle davon ausgeführt wurden.
In diesem Fall kann eine Transaktion gestartet werden, welche in Yii
durch eine [CDbTransaction]-Instanz repräsentiert wird:
- Beginne die Transaktion.
- Führe die Abfragen der Reihe nach aus. Alle Datenbankaktualisierungen sind für die
Außenwelt unsichtbar.
- Abschließen der Transaktion mit Commit. Die Aktualisierungen werden sichtbar, falls
die Transaktion erfolgreich war.
- Falls eine der Anfragen fehlschlägt, wird die ganze Transaktion
zurückgefahren.
Der obige Ablauf kann mit dem folgenden Code implementiert werden:
~~~
[php]
$transaction=$connection->beginTransaction();
try
{
$connection->createCommand($sql1)->execute();
$connection->createCommand($sql2)->execute();
//.... weitere SQL Abfragen
$transaction->commit();
}
catch(Exception $e) // Eine Exception wird ausgelöst, falls eine Abfrage fehlschlägt
{
$transaction->rollBack();
}
~~~
Binden von Parametern
---------------------
Um [SQL-Injection](http://de.wikipedia.org/wiki/SQL-Injection)-Angriffe zu
vermeiden, und um die Geschwindigkeit mehrfach verwendeter SQL-Anweisungen zu verbessern,
kann man eine SQL Anweisung mit optionalen Platzhaltern für Parameter
"vorbereiten" (engl. prepare). Die Platzhalter werden während des
Bindungsprozesses durch die eigentlichen Parameter ersetzt.
Die Platzhalter für Parameter können entweder benannt (durch eine eindeutige
Zeichenkette) oder unbenannt (dargestellt durch Fragezeichen) sein. Rufen Sie
[CDbCommand::bindParam()] oder [CDbCommand::bindValue()] auf, um diese Platzhalter
durch die eigentlichen Parameter zu ersetzen. Die Parameter müssen nicht in
Anführungszeichen gesetzt werden. Der zugrundeliegende Datenbanktreiber erledigt
das für sie. Das Binden der Parameter muss
vor der Ausführung der SQL Anweisung erfolgen.
~~~
[php]
// SQL-Anweisung mit zwei Platzhaltern ":username" und ":email"
$sql="INSERT INTO users(username, email) VALUES(:username,:email)";
$command=$connection->createCommand($sql);
// Ersetze den Platzhalter ":username" durch den tatsächlichen Benutzernamen
$command->bindParam(":username",$username,PDO::PARAM_STR);
// Ersetze den Platzhalter ":email" durch die tatsächliche E-Mail Adresse
$command->bindParam(":email",$email,PDO::PARAM_STR);
$command->execute();
// Füge eine weitere Zeile mit einem neuen Parametersatz ein
$command->bindParam(":username",$username2,PDO::PARAM_STR);
$command->bindParam(":email",$email2,PDO::PARAM_STR);
$command->execute();
~~~
Die Methoden [bindParam()|CDbCommand::bindParam] und [bindValue()|CDbCommand::bindValue]
sind sehr ähnlich. Der einzige Unterschied besteht darin,
dass erstere einen Parameter als Referenz auf eine PHP-Variable, letztere dagegen
mit einem Wert bindet. Für Parameter, die für einen großen Block von Daten
stehen, ist ersteres aus Performancegründen zu bevorzugen.
Weitere Einzelheiten zum Binden von Parametern finden Sie in der [einschlägigen PHP
Dokumentation](http://www.php.net/manual/en/pdostatement.bindparam.php).
Binden von Spalten
------------------
Beim Auslesen von Abfrageergebnissen kann man auch Spalten an PHP Variablen
binden, so dass sie jedes Mal beim Zugriff auf eine Zeile automatisch mit den
aktuellen Daten befüllt werden.
~~~
[php]
$sql="SELECT username, email FROM users";
$dataReader=$connection->createCommand($sql)->query();
// Binde die 1. Spalte (username) an die Variable $username
$dataReader->bindColumn(1,$username);
// Binde die 2. Spalte (email) an die Variable $email
/$dataReader->bindColumn(2,$email);
while($dataReader->read()!==false)
{
// $username und $email enthalten den Benutzernamen und die E-Mail-Adresse der aktuellen Zeile
}
~~~
Verwenden eines Tabellenpräfix
------------------------------
Seit Version 1.1.0 unterstützt Yii auch Tabellenpräfixe. Ein Präfix ist ein
String, der allen Tabellennamen der aktuellen Verbindung vorangestellt wird.
Es wird meist in gemeinsam genutzten Hosting-Umgebungen verwendet, wo mehrere
Anwendungen sich eine einzelne Datenbank teilen und zur Unterscheidung
verschiedene Präfixe verwenden. Eine Anwendung könnte z.B. `tbl_`, eine andere
`yii_` als Präfix verwenden.
Um ein Tabellenpräfix zu verwenden, konfigurieren Sie es in der Eigenschaft
[CDbConnection::tablePrefix]. In SQL-Ausdrücken verwenden Sie dann
`{{TabellenName}}` um sich auf Tabellennamen zu beziehen, wobei `TabellenName`
für den Namen der Tabelle ohne Präfix steht. Wenn die Datenbank z.B. eine
Tabelle `tbl_users` enthält und `tbl_` als Tabellenpräfix konfiguriert wurde,
können wir so eine Abfrage auf dieser Tabelle durchführen:
~~~
[php]
$sql='SELECT * FROM {{users}}';
$users=$connection->createCommand($sql)->queryAll();
~~~
<div class="revision">$Id: database.dao.txt 1479 2009-10-23 13:24:20Z qiang.xue $</div>