Data Access Objects (DAO)
Data Access Objects (DAO) tillhandahåller ett generellt programmeringsgränssnitt (API) för att ge tillgång till data lagrad i olika databahshanterare (DBMS). Detta medför att den underliggande databashanteraren kan bytas till en annan utan behov av ändringar i den kod som använder DAO för dataåtkomst.
Yii:s DAO har byggts ovanpå PHP Data Objects
(PDO)-tillägget, vilket tillhandahåller
enhetlig åtkomst till många populära databashanterare såsom MySQL, PostgreSQL.
Av denna anledning behöver PDO-tillägget och den databasspecifika PDO-
drivrutinen (t.ex. PDO_MYSQL
) installeras innan Yii:s PDO används.
Yii:s DAO består i huvudsak av följande fyra klasser:
- CDbConnection: representerar en anslutning till en databas.
- CDbCommand: representerar en SQL-sats som skall exekveras mot en databas.
- CDbDataReader: representerar en icke-reversibel följd av rader ur en frågas resultatmängd.
- CDbTransaction: representerar en databastransaktion.
I följande stycken introduceras användning av Yii:s DAO i olika scenarier.
Upprätta en databasanslutning
För att upprätta en databasanslutning, skapa en instans av CDbConnection och aktivera den. Ett namn på en datakälla (DSN) erfordras för att specificera nödvändig information för anslutning till databasen. Ett användarnamn och ett lösenord kan också behövas för att upprätta anslutningen. En exception signaleras i händelse av att ett fel uppstår under upprättandet av anslutningen (t.ex. felaktig DSN eller ogiltigt användarnamn/lösenord).
$connection=new CDbConnection($dsn,$username,$password); // establish connection. You may try...catch possible exceptions $connection->active=true; ...... $connection->active=false; // close connection
Formatet för ett DSN bestäms av vilken databasspecifik PDO-drivrutin som används. Generellt sett består ett DSN av namnet på PDO-drivrutinen följt av ett kolon, följt av drivrutinsspecifik anslutningssyntax. Se PDO-dokumentationen för fullständig information. Nedan återges en lista med vanligtvis använda DSN-format:
- 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
Eftersom CDbConnection är en utvidgning av CApplicationComponent, kan vi
även använda den som just en
applikationskomponent.
För att göra så, konfigurera in en db
(eller annat namn) applikationskomponent i
applikationskonfigurationen
enligt följande,
array( ...... 'components'=>array( ...... 'db'=>array( 'class'=>'CDbConnection', 'connectionString'=>'mysql:host=localhost;dbname=testdb', 'username'=>'root', 'password'=>'password', 'emulatePrepare'=>true, // erfordras i vissa MySQL-installationer ), ), )
Därefter kan databasanslutningen tillgås via Yii::app()->db
som redan är
automatiskt aktiverad, utom i det fall CDbConnection::autoConnect uttryckligen
konfigurerats till false. Med användande av detta tillvägagångssätt kan en enda
DB-anslutning delas av kod på flera ställen.
Exekvering av SQL-satser
När en databasanslutning väl har etablerats, kan SQL-satser exekveras med hjälp av CDbCommand. Man skapar en instans av CDbCommand genom anrop till CDbConnection::createCommand() med SQL-satsen angiven:
$connection=Yii::app()->db; // assuming you have configured a "db" connection // If not, you may explicitly create a connection: // $connection=new CDbConnection($dsn,$username,$password); $command=$connection->createCommand($sql); // if needed, the SQL statement may be updated as follows: // $command->text=$newSQL;
En SQL-sats exekveras via CDbCommand på ett av följande två sätt:
execute(): genomför en SQL-sats som inte returnerar rader, såsom
INSERT
,UPDATE
andDELETE
. Vid felfritt genomförande returneras antalet rader som omfattades av operationen.query(): genomför en SQL-sats som returnerar rader av data (eg. "påsar"), såsom
SELECT
. Vid felfritt genomförande, returneras en instans av CDbDataReader från vilken man kan traversera den resulterande mängden av rader. För bekvämlighets skull har även en uppsättningqueryXXX()
-metoder implementerats, vilka direkt returnerar respektive frågeresultat.
En exception signaleras om ett fel skulle inträffa under exekveringen av SQL-satser.
$rowCount=$command->execute(); // exekvera SQL som inte är en fråga $dataReader=$command->query(); // exekvera en SQL-fråga $rows=$command->queryAll(); // exekvera fråga och returnera alla resultatrader $row=$command->queryRow(); // exekvera fråga och returnera första resultatraden $column=$command->queryColumn(); // exekvera fråga och returnera första resultatkolumnen $value=$command->queryScalar(); // exekvera fråga och returnera första fältet i första raden
Hämta frågeresultat
Då CDbCommand::query() genererat CDbDataReader-instansen, kan man hämta
resulterande datarader genom att repetitivt anropa CDbDataReader::read(). Man
kan även använda CDbDataReader i en i PHP-språket tillgänglig foreach
-sats
för att hämta data rad för rad.
$dataReader=$command->query(); // calling read() repeatedly until it returns false while(($row=$dataReader->read())!==false) { ... } // using foreach to traverse through every row of data foreach($dataReader as $row) { ... } // retrieving all rows at once in a single array $rows=$dataReader->readAll();
Märk: Till skillnad från query(), returnerar alla
queryXXX()
-metoder data direkt. Till exempel returnerar queryRow()|CDbCommand::queryRow] en array som representerar den första raden i frågeresultatet.
Användning av transaktioner
När en applikation exekverar ett antal databasoperationer, som var och en läser information från och/eller skriver information till databasen, är det viktigt att försäkra sig om att databasen inte lämnas med några operationer ofullständigt utförda. En transaktion, representerad i Yii som en instans av CDbTransaction, kan inledas för att säkerställa detta:
- Starta (begin) transaktionen.
- Exekvera frågorna/operationerna en och en. Eventuella uppdateringar av databasen kan inte ses av av världen utanför.
- Bekräfta (commit) transaktionen. Uppdateringar blir nu synliga eftersom transaktionen lyckades.
- Om en av operationerna misslyckades reverseras hela transaktionen (rollback).
Ovanstående arbetsflöde kan implementeras med hjälp av följande kod:
$transaction=$connection->beginTransaction(); try { $connection->createCommand($sql1)->execute(); $connection->createCommand($sql2)->execute(); //.... other SQL executions $transaction->commit(); } catch(Exception $e) // an exception is raised if a query fails { $transaction->rollBack(); }
Koppling av parametrar
För att undvika SQL- injekteringsattacker samt för förbättrad prestanda vid upprepad exekvering av SQL-satser, kan man i förekommande fall förbereda ("prepare") en SQL-sats med platsmarkörer för parametrar, som senare - vid koppling av parametrar (parameter binding) - kommer att ersättas med aktuella parametrar.
Parameterplatsmarkörerna kan antingen var namngivna (representerade av unika symboler) eller icke-namngivna (representerade av frågetecken). Anropa CDbCommand::bindParam() eller CDbCommand::bindValue() för att ersätta dessa platsmarkörer med de aktuella parametrarna. Parametrarna behöver inte omges av citationstecken; den underliggande databasdrivrutinen utför detta. Parameterkoppling måste ske innan SQL-satsen exekveras.
// an SQL with two placeholders ":username" and ":email" $sql="INSERT INTO tbl_user (username, email) VALUES(:username,:email)"; $command=$connection->createCommand($sql); // replace the placeholder ":username" with the actual username value $command->bindParam(":username",$username,PDO::PARAM_STR); // replace the placeholder ":email" with the actual email value $command->bindParam(":email",$email,PDO::PARAM_STR); $command->execute(); // insert another row with a new set of parameters $command->bindParam(":username",$username2,PDO::PARAM_STR); $command->bindParam(":email",$email2,PDO::PARAM_STR); $command->execute();
Metoderna bindParam() och bindValue() är mycket snarlika. Den enda skillnaden är att den förra kopplar en parameter till en PHP-variabelreferens, den senare med ett värde. För parametrar som representerar stora block av dataminne är den förra metoden - av prestandaskäl - att föredra.
För fler detaljer om parameterkoppling, se den tillämpliga PHP- dokumentationen.
Koppling av kolumner
Vid hämtning av frågeresultat kan man också koppla kolumner till PHP-variabler så att de automatiskt uppdateras med senaste data var gång en rad hämtas.
$sql="SELECT username, email FROM tbl_user"; $dataReader=$connection->createCommand($sql)->query(); // bind the 1st column (username) with the $username variable $dataReader->bindColumn(1,$username); // bind the 2nd column (email) with the $email variable $dataReader->bindColumn(2,$email); while($dataReader->read()!==false) { // $username and $email contain the username and email in the current row }
Användning av tabellprefix
Yii erbjuder inbyggt stöd för användning av tabellprefix. Tabellprefix innebär
att en sträng sätts in före namnen på tabeller i den för tillfället anslutna
databasen. Detta kommer mest till användning i en webbhotellmiljö där fler än en
applikation delar samma databas och applikationerna hålls åtskilda genom att
tabellprefix sätts in före tabellnamnen. Till exempel kan en applikation använda
tbl_
som prefix, medan en annan använder yii_
.
För att använda tabellprefix, konfigurera propertyn CDbConnection::tablePrefix med
det önskade tabellprefixet. Därefter används {{TableName}}
- där TableName
innebär
tabellnamnet utan prefix - i SQL-satser för att referera till tabeller. Exempelvis,
om databasen innehåller en tabell tbl_user
, och tbl_
är konfigurerat som
tabellprefix, kan följande kod användas i en fråga angående användare:
$sql='SELECT * FROM {{user}}'; $users=$connection->createCommand($sql)->queryAll();