mirror of
https://github.com/yiisoft/yii.git
synced 2026-03-12 02:56:55 +01:00
206 lines
15 KiB
Plaintext
206 lines
15 KiB
Plaintext
Обʼєкти доступу до даних (DAO)
|
||
==============================
|
||
|
||
Обʼєкти доступу до даних (DAO) надають загальний API для доступу до даних, що зберігаються в різних СУБД. Це дозволяє без проблем змінити використовувану СУБД на будь-яку іншу без необхідності зміни коду, що використовує DAO для доступу до даних.
|
||
|
||
Yii DAO є надбудовою над [PHP Data Objects (PDO)](http://php.net/manual/en/book.pdo.php) -
|
||
розширенням, яке надає уніфікований доступ до даних багатьох популярних СУБД, таких, як MySQL, PostgreSQL. Для використання Yii DAO необхідно, щоб були встановлені розширення PDO і драйвер PDO, що відповідає використовуваній базі даних (наприклад, `PDO_MYSQL`).
|
||
|
||
Yii DAO складається із чотирьох основних класів:
|
||
|
||
- [CDbConnection]: представляє підключення до бази даних;
|
||
- [CDbCommand]: представляє вираз SQL та його виконання;
|
||
- [CDbDataReader]: представляє односпрямований потік рядків з даних, що повертаються у відповідь на SQL-запит;
|
||
- [CDbTransaction]: представляє транзакції бази даних.
|
||
|
||
Нижче ми проілюструємо використання Yii DAO.
|
||
|
||
Зʼєднання з базою даних
|
||
-----------------------
|
||
|
||
Для встановлення зʼєднання із базою необхідно створити екземпляр класу [CDbConnection] і активувати його. Додаткову інформацію, необхідну для підключення до БД (хост, порт, імʼя користувача, пароль тощо), вказуємо у DSN. У разі виникнення помилки в процесі зʼєднання з БД, буде викликано виключення (наприклад, невірний DSN або неправильні імʼя користувача/пароль).
|
||
|
||
~~~
|
||
[php]
|
||
$connection=new CDbConnection($dsn,$username,$password);
|
||
// встановлюємо зʼєднання. Можна спробувати try…catch можливих виключень
|
||
$connection->active=true;
|
||
…
|
||
$connection->active=false; // close connection
|
||
~~~
|
||
|
||
Формат DSN залежить від використовуваного драйвера PDO. Як правило, DSN складається із імені драйвера PDO,
|
||
за яким слідує двокрапка, а далі вказуються параметри підключення, відповідні синтаксису підключення
|
||
використовуваного драйвера. Докладніше з цим можна ознайомитися в [документації по PDO](http://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#application-component). Для цього потрібно налаштувати
|
||
компонент `db` у [конфігурації додатка](/doc/guide/basics.application#application-configuration)
|
||
наступним чином:
|
||
|
||
~~~
|
||
[php]
|
||
array(
|
||
…
|
||
'components'=>array(
|
||
…
|
||
'db'=>array(
|
||
'class'=>'CDbConnection',
|
||
'connectionString'=>'mysql:host=localhost;dbname=testdb',
|
||
'username'=>'root',
|
||
'password'=>'password',
|
||
'emulatePrepare'=>true, // необхідно для деяких версій MySQL
|
||
),
|
||
),
|
||
)
|
||
~~~
|
||
|
||
Тепер ми можемо отримати доступ до зʼєднання з БД через `Yii::app()->db`. Щоб зʼєднання не активувалося автоматично, необхідно встановити значення [CDbConnection::autoConnect] в `false`. Цей спосіб дає нам можливість використання одного підключення до БД в будь-якому місці коду.
|
||
|
||
Виконання SQL-виразів
|
||
---------------------
|
||
|
||
Коли зʼєднання з БД встановлено, ми можемо виконувати SQL-вирази, використовуючи [CDbCommand]. Для цього створюємо екземпляр [CDbCommand] шляхом виклику [CDbConnection::createCommand()] із зазначенням SQL-виразу:
|
||
|
||
~~~
|
||
[php]
|
||
$connection=Yii::app()->db; // так можна зробити, якщо в конфігурації описаний компонент зʼєднання "db"
|
||
// Якщо не описаний - можна створити зʼєднання явно:
|
||
// $connection=new CDbConnection($dsn,$username,$password);
|
||
$command=$connection->createCommand($sql);
|
||
// якщо необхідно, SQL-вираз можна оновити:
|
||
// $command->text=$newSQL;
|
||
~~~
|
||
|
||
Існує два варіанти виконання SQL-виразу з використанням [CDbCommand]:
|
||
|
||
- [execute()|CDbCommand::execute]: виконує SQL-вирази типу `INSERT`, `UPDATE` і `DELETE`. У разі успішного виконання, повертає кількість оброблених рядків;
|
||
|
||
- [query()|CDbCommand::query]: виконує SQL-вирази, які повертають набори даних, наприклад, типу `SELECT`. У разі успішного виконання, повертає екземпляр класу [CDbDataReader], через який доступні отримані дані. Для зручності також реалізовані методи `queryXXX ()`, повертають результати запиту напряму.
|
||
|
||
Якщо в процесі виконання SQL-виразу виникне помилка, буде викликано виключення.
|
||
|
||
~~~
|
||
[php]
|
||
$rowCount=$command->execute(); // виконання вирази типу `INSERT`, `UPDATE` та `DELETE`
|
||
$dataReader=$command->query(); // виконання вирази типу `SELECT`
|
||
$rows=$command->queryAll(); // запит і повернення всіх рядків результату
|
||
$row=$command->queryRow(); // запит і повернення першого рядка результату
|
||
$column=$command->queryColumn(); // запит і повернення першого стовпця результату
|
||
$value=$command->queryScalar(); // запит і повернення першого поля в першому рядку
|
||
~~~
|
||
|
||
Обробка результатів запиту
|
||
--------------------------
|
||
|
||
Після того, як [CDbCommand::query()] створює екземпляр класу [CDbDataReader], ми можемо отримати дані порядково шляхом повторного виклику методу [CDbDataReader::read()]. Для отримання даних рядок за рядком можна також використовувати [CDbDataReader] в конструкціях `foreach`.
|
||
|
||
~~~
|
||
[php]
|
||
$dataReader=$command->query();
|
||
// багаторазово викликаємо read() до повернення методом значення false
|
||
while(($row=$dataReader->read())!==false) { … }
|
||
// використовуємо foreach для порядкового обходу даних
|
||
foreach($dataReader as $row) { … }
|
||
// отримуємо всі рядки разом в одному масиві
|
||
$rows=$dataReader->readAll();
|
||
~~~
|
||
|
||
> Note|Примітка: Всі методи `queryXXX()`, на відміну від [query()|CDbCommand::query], повертають
|
||
всі дані напряму. Наприклад, метод [queryRow()|CDbCommand::queryRow] повертає масив з першим рядком результату запиту.
|
||
|
||
Використання транзакцій
|
||
-----------------------
|
||
|
||
У випадку, коли додаток виконує декілька запитів, кожен з яких щось пише або читає з БД, важливо пересвідчитися, що набір запитів виконано повністю, а не наполовину. У цій ситуації можна скористатися транзакціями, що надаються екземпляром класу [CDbTransaction]:
|
||
|
||
- початок транзакції;
|
||
- виконання запитів по черзі, всі зміни даних у БД недоступні поза базою;
|
||
- підтвердження транзакції, якщо результат транзакції позитивний, то зміни стають доступні;
|
||
- якщо виникає помилка при виконанні будь-якого запиту, то вся транзація відкочується назад.
|
||
|
||
Цю послідовність дій можна реалізувати наступним чином:
|
||
|
||
~~~
|
||
[php]
|
||
$transaction=$connection->beginTransaction();
|
||
try
|
||
{
|
||
$connection->createCommand($sql1)->execute();
|
||
$connection->createCommand($sql2)->execute();
|
||
//… інші SQL запити
|
||
$transaction->commit();
|
||
}
|
||
catch(Exception $e) // у разі помилки при виконанні запиту викидається виключення
|
||
{
|
||
$transaction->rollback();
|
||
}
|
||
~~~
|
||
|
||
Звʼязування параметрів
|
||
----------------------
|
||
|
||
З метою уникнення [SQL-інʼєкцій](http://ru.wikipedia.org/wiki/SQL_injection) і поліпшення продуктивності при виконанні повторно використовуваних SQL-виразів, ми можемо «готувати» SQL-вираз з маркерами параметрів (placeholder), які в процесі привʼязки будуть замінюватися на реальні значення.
|
||
|
||
Маркери параметрів можуть бути іменованими (унікальні маркери) або неіменовані (знаки питання). Для заміни маркерів на реальні значення потрібно викликати [CDbCommand::bindParam()] або [CDbCommand::bindValue()]. Додавати лапки до параметрів немає необхідності, тому що використовуваний драйвер бази даних все зробить сам. Звʼязування параметрів повинно бути завершено до виконання SQL-виразу.
|
||
|
||
~~~
|
||
[php]
|
||
// вираз SQL з двома маркерами «:username» та «:email»
|
||
$sql="INSERT INTO tbl_user(username, email) VALUES(:username,:email)";
|
||
$command=$connection->createCommand($sql);
|
||
// міняємо маркер «:username» на відповідне значення імені користувача
|
||
$command->bindParam(":username",$username,PDO::PARAM_STR);
|
||
// міняємо маркер «:email» на відповідне значення електронної пошти
|
||
$command->bindParam(":email",$email,PDO::PARAM_STR);
|
||
$command->execute();
|
||
// вставляємо наступний рядок з новими параметрами
|
||
$command->bindParam(":username",$username2,PDO::PARAM_STR);
|
||
$command->bindParam(":email",$email2,PDO::PARAM_STR);
|
||
$command->execute();
|
||
~~~
|
||
|
||
Методи [bindParam()|CDbCommand::bindParam] і [bindValue()|CDbCommand::bindValue] дуже схожі, єдина відмінність полягає в тому, що перший звʼязує параметр до посилання на змінну PHP, а другий - до значення. Для параметрів, що представляють великий обсяг даних, з точки зору продуктивності краще використовувати метод [bindParam()|CDbCommand::bindParam].
|
||
|
||
Детальніше про звʼязування параметрів можна дізнатися у [відповідній документації PHP](http://php.net/manual/en/pdostatement.bindparam.php).
|
||
|
||
|
||
Звʼязування полів
|
||
-----------------
|
||
|
||
При обробці результатів запиту ми також можемо привʼязати поля таблиці до змінних PHP. Це дозволяє автоматично підставляти значення змінних для кожного рядка:
|
||
|
||
~~~
|
||
[php]
|
||
$sql="SELECT username, email FROM tbl_user";
|
||
$dataReader=$connection->createCommand($sql)->query();
|
||
// привʼязуємо перше поле (username) до змінної $username
|
||
$dataReader->bindColumn(1,$username);
|
||
// привʼязуємо друге поле (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: database.dao.txt 2890 2011-01-18 15:58:34Z qiang.xue $</div> |