Files
yii/docs/guide/ru/database.dao.txt
2010-09-05 13:02:42 +00:00

246 lines
16 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 текущей строки
}
~~~
Использование префикса таблиц
-----------------------------
Начиная с версии 1.1.0, 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 2266 2010-07-17 13:58:30Z qiang.xue $</div>