Объекты доступа к данным (DAO) предоставляют общий API для доступа к данным, хранящимся в различных СУБД. Это позволяет без проблем поменять используемую СУБД на любую другую без необходимости изменения кода, использующего DAO для доступа к данным.
Yii DAO является надстройкой над PHP Data Objects (PDO) -
расширением, которое предоставляет унифицированный доступ к данным многих популярных
СУБД, таких, как MySQL, PostgreSQL. Для использования Yii DAO необходимо, чтобы
были установлены расширение PDO и драйвер PDO, соответствующий используемой базе данных (например, PDO_MYSQL
).
Yii DAO состоит из четырех основных классов:
Ниже мы проиллюстрируем использование Yii DAO.
Для установления соединения с базой необходимо создать экземпляр класса CDbConnection и активировать его. Дополнительную информацию, необходимую для подключения к БД (хост, порт, имя пользователя, пароль и пр.), указываем в DSN. В случае возникновения ошибки в процессе соединения с БД, будет вызвано исключение (например, неверный DSN или неправильные имя пользователя/пароль).
$connection=new CDbConnection($dsn,$username,$password);
// устанавливаем соединение. Можно попробовать try...catch возможных исключений
$connection->active=true;
......
$connection->active=false; // close connection
Формат DSN зависит от используемого драйвера PDO. Как правило, DSN состоит из имени драйвера PDO, за которым следует двоеточие, а далее указываются параметры подключения, соответствующие синтаксису подключения используемого драйвера. Подробнее с этим можно ознакомиться в документации по PDO. Ниже представлены несколько основных форматов DSN:
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
Поскольку CDbConnection является подклассом CApplicationComponent, то мы можем использовать его
в качестве компонента. Для этого нужно настроить
компонент db
в конфигурации приложения
следующим образом:
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-выражения, используя CDbCommand. Для этого создаем экземпляр CDbCommand путем вызова CDbConnection::createCommand() с указанием SQL-выражения:
$command=$connection->createCommand($sql);
// если необходимо, SQL-выражение можно обновить:
// $command->text=$newSQL;
Существует два варианта исполнения SQL-выражения с использованием CDbCommand:
execute(): выполняет SQL-выражения типа INSERT
, UPDATE
и DELETE
.
В случае успешного исполнения, возвращает количество обработанных строк;
query(): выполняет SQL-выражения, возвращающие наборы данных, например, типа SELECT
.
В случае успешного исполнения, возвращает экземпляр класса CDbDataReader, через который доступны полученные данные.
Для удобства также реализованы методы queryXXX()
, возвращающие результаты запроса напрямую.
Если в процессе выполнения SQL-выражения возникнет ошибка, будет вызвано исключение.
$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
.
$dataReader=$command->query();
// многократно вызываем read() до возврата методом значения false
while(($row=$dataReader->read())!==false) { ... }
// используем foreach для построчного обхода данных
foreach($dataReader as $row) { ... }
// получаем все строки разом в одном массиве
$rows=$dataReader->readAll();
Примечание: Все методы
queryXXX()
, в отличие от query(), возвращают все данные напрямую. Например, метод queryRow() возвращает массив с первой строкой результата запроса.
В случае, когда приложение выполняет несколько запросов, каждый из которых что-то пишет или читает из БД, важно удостовериться, что набор запросов выполнен полностью, а не наполовину. В этой ситуации можно воспользоваться транзакциями, представляемыми экземпляром класса CDbTransaction:
Эту последовательность действий можно реализовать следующим образом:
$transaction=$connection->beginTransaction();
try
{
$connection->createCommand($sql1)->execute();
$connection->createCommand($sql2)->execute();
//.... прочие SQL запросы
$transaction->commit();
}
catch(Exception $e) // в случае ошибки при выполнении запроса выбрасывается исключение
{
$transaction->rollBack();
}
С целью избежания SQL-инъекций и улучшения производительности при выполнении повторно используемых SQL-выражений, мы можем "подготавливать" SQL-выражение с маркерами параметров (placeholder), которые в процессе привязки будут заменяться на реальные значения.
Маркеры параметров могут быть именованными (уникальные маркеры) или неименованными (вопросительные знаки). Для замены маркеров на реальные значения нужно вызвать CDbCommand::bindParam() или CDbCommand::bindValue(). Добавлять кавычки к параметрам нет необходимости, т.к. используемый драйвер базы данных все сделает сам. Связывание параметров должно быть завершено до исполнения SQL-выражения.
// выражение SQL с двумя маркерами ":username" и ":email"
$sql="INSERT INTO users(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() и bindValue() очень похожи, единственное различие состоит в том, что первый привязывает параметр к ссылке на переменную PHP, а второй - к значению. Для параметров, представляющих большой объем данных, с точки зрения производительности предпочтительнее использовать метод bindParam().
Подробнее о связывании параметров можно узнать в соответствующей документации PHP.
При обработке результатов запроса мы также можем привязать поля таблицы к переменным PHP. Это позволяет автоматически обновлять значения переменных при каждом получении строки на значения, которые она содержит.
$sql="SELECT username, email FROM users";
$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 текущей строки
}
Signup or Login in order to comment.