Files
yii/docs/guide/uk/database.dao.txt

206 lines
15 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
Обʼєкти доступу до даних (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>