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)
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:
Nachfolgend zeigen wir den Einsatz von Yii-DAO in unterschiedlichen Anwendungsfällen.
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.
$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 für weitere Informationen. Nachfolgend eine Liste der gebräuchlichsten DSN-Formate:
sqlite:/path/to/dbfile
mysql:host=localhost;dbname=testdb
pgsql:host=localhost;port=5432;dbname=testdb
mssql:host=localhost;dbname=testdb
oci:dbname=//localhost:1521/testdb
Da CDbConnection von CApplicationComponent abgeleitet ist, können wir sie auch
als Applikationskomponente
einsetzen. Dazu muss eine Anwendungskomponente db
(die auch anderse benannt
sein kann) in der Applikationskonfiguration
wie folgt konfiguriert werden:
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.
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:
$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(): 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(): 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,
$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
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.
$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();
Hinweis: Anders als query() liefern alle
queryXXX()
-Methoden die Daten direkt zurück. Zum Beispiel gibt queryRow() ein Array zurück, das die erste Zeile des Abfrageergebnisses repräsentiert.
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:
Der obige Ablauf kann mit dem folgenden Code implementiert werden:
$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();
}
Um 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.
// 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() und 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.
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.
$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
}
Signup or Login in order to comment.