mirror of
https://github.com/yiisoft/yii.git
synced 2026-03-06 00:04:07 +01:00
388 lines
19 KiB
Plaintext
388 lines
19 KiB
Plaintext
Миграции
|
||
========
|
||
|
||
> Note|Примечание: Миграции доступны с версии 1.1.6.
|
||
|
||
Как и исходный код, структура базы данных изменяется в процессе разработки
|
||
и поддержки приложения. К примеру, во время разработки может понадобиться
|
||
добавить новую таблицу или уже после размещения приложения на сервере добавить
|
||
индекс или столбец. При этом важно отслеживать изменения в структуре базы
|
||
данных (называемые **миграциями**) также, как мы делаем это для нашего исходного кода.
|
||
Если исходный код и база данных не соответствуют друг другу, скорее всего,
|
||
всё приложение не будет работать. Именно поэтому в Yii есть поддержка миграций,
|
||
позволяющая отслеживать изменения в базе данных, применять миграции или откатывать
|
||
уже применённые.
|
||
|
||
Ниже приведён пошаговый процесс использования миграций при разработке:
|
||
|
||
1. Иван создаёт новую миграцию (например, создающую новую таблицу).
|
||
2. Иван заливает её в систему контроля версий (SVN, GIT или другую).
|
||
3. Андрей обновляется из системы контроля версий и получает новую миграцию.
|
||
4. Андрей применяет миграцию к своей локальной базе данных.
|
||
|
||
|
||
В Yii управление миграциями производится через консольную команду `yiic migrate`,
|
||
которая поддерживает создание новых миграций, применение, откат и повторное
|
||
применение миграций, просмотр истории миграций и новых миграций.
|
||
|
||
|
||
> Note|Примечание: При работе с командой `migrate` рекомендуется использовать
|
||
> yiic приложения (то есть после `cd path/to/protected`), а не yiic из
|
||
> директории `framework`. Убедитесь, что директория `protected\migrations` существует и
|
||
> доступна для записи. Также проверьте настройки соединения с базой данных в `protected/config/console.php`.
|
||
|
||
|
||
Создание миграций
|
||
-----------------
|
||
|
||
Для создания новой миграции (например, создающей таблицу для новостей), мы должны
|
||
ввести в консоли:
|
||
|
||
~~~
|
||
yiic migrate create <name>
|
||
~~~
|
||
|
||
Обязательный параметр `name` должен содержать очень краткое описание миграции
|
||
(например, `create_news_table`). Как будет показано далее,
|
||
этот параметр используется как часть имени класса миграции, поэтому использовать
|
||
можно только буквы, цифры и знаки подчёркивания.
|
||
|
||
~~~
|
||
yiic migrate create create_news_table
|
||
~~~
|
||
|
||
Приведённая команда создаст в директории `protected/migrations` файл
|
||
`m101129_185401_create_news_table.php`, содержащий следующее:
|
||
|
||
~~~
|
||
[php]
|
||
class m101129_185401_create_news_table extends CDbMigration
|
||
{
|
||
public function up()
|
||
{
|
||
}
|
||
|
||
|
||
public function down()
|
||
{
|
||
echo "m101129_185401_create_news_table does not support migration down.\n";
|
||
return false;
|
||
}
|
||
|
||
/*
|
||
// если требуется выполнить изменения внутри транзакции, используйте safeUp/safeDown
|
||
// вместо up/down
|
||
public function safeUp()
|
||
{
|
||
}
|
||
|
||
public function safeDown()
|
||
{
|
||
}
|
||
*/
|
||
}
|
||
~~~
|
||
|
||
Стоит отметить, что имя класса совпадает с именем файла и строится как
|
||
`m<timestamp>_<name>`, где `<timestamp>` — это время создания миграции в UTC
|
||
(в формате `yymmdd_hhmmss`), а `<name>` — то, что передано в параметре
|
||
`name` команды.
|
||
|
||
Метод `up()` должен содержать код, выполняющий миграцию, а метод `down()` может
|
||
содержать код, отменяющий сделанное в `up()`.
|
||
|
||
Иногда реализовать `down()` не получается. К примеру, если в `up()` из таблицы
|
||
удаляются данные, в `down()` вернуть их не получится. В этом случае миграция
|
||
называется необратимой, что означает невозможность возврата к предыдущему
|
||
состоянию базы данных. В приведённом выше коде метод `down()` возвращает `false`.
|
||
Это означает невозможность отката миграции.
|
||
|
||
> Info|Информация: Начиная с версии 1.1.7, если метод `up()` или метод `down()`
|
||
> возвращают `false`, все последующие миграции не будут применены. В 1.1.6 для
|
||
> этого было необходимо выкинуть исключение.
|
||
|
||
Рассмотрим в качестве примера миграцию, создающую таблицу с новостями.
|
||
|
||
~~~
|
||
[php]
|
||
class m101129_185401_create_news_table extends CDbMigration
|
||
{
|
||
public function up()
|
||
{
|
||
$this->createTable('tbl_news', array(
|
||
'id' => 'pk',
|
||
'title' => 'string NOT NULL',
|
||
'content' => 'text',
|
||
));
|
||
}
|
||
|
||
public function down()
|
||
{
|
||
$this->dropTable('tbl_news');
|
||
}
|
||
}
|
||
~~~
|
||
|
||
Базовый класс [CDbMigration] предоставляет набор методов для работы с данными
|
||
и структурой базы данных. К примеру, при помощи [CDbMigration::createTable]
|
||
можно создать новую таблицу, а [CDbMigration::insert] добавит строку с данными.
|
||
Все эти методы используют подключение к базе данных, возвращаемое
|
||
[CDbMigration::getDbConnection()], что по умолчанию эквивалентно `Yii::app()->db`.
|
||
|
||
> Info|Информация: Как вы могли заметить, методы [CDbMigration] очень похожи на
|
||
методы [CDbCommand]. И это на самом деле так. Единственно отличие состоит в том, что
|
||
методы [CDbMigration] подсчитывают затрачиваемое на их выполнение время и
|
||
выводят сообщения о параметрах методов.
|
||
|
||
|
||
Транзакционные миграции
|
||
-----------------------
|
||
|
||
> Info|Информация: Данная возможность поддерживается, начиная с версии 1.1.7.
|
||
|
||
При применении сложных миграций для сохранения целостности данных
|
||
требуется либо выполнить все запросы, либо, если запрос не выполнился,
|
||
отменить предыдущие запросы. Для достижения этой цели можно использовать
|
||
транзакции.
|
||
|
||
Можно начать транзакцию явно и заключить в неё весь код, меняющий базу данных:
|
||
|
||
~~~
|
||
[php]
|
||
class m101129_185401_create_news_table extends CDbMigration
|
||
{
|
||
public function up()
|
||
{
|
||
$transaction=$this->getDbConnection()->beginTransaction();
|
||
try
|
||
{
|
||
$this->createTable('tbl_news', array(
|
||
'id' => 'pk',
|
||
'title' => 'string NOT NULL',
|
||
'content' => 'text',
|
||
));
|
||
$transaction->commit();
|
||
}
|
||
catch(Exception $e)
|
||
{
|
||
echo "Exception: ".$e->getMessage()."\n";
|
||
$transaction->rollback();
|
||
return false;
|
||
}
|
||
}
|
||
|
||
// …похожий код для down()
|
||
}
|
||
~~~
|
||
|
||
А можно сделать это проще, реализовав метод `safeUp()` вместо `up()` и `safeDown()`
|
||
вместо `down()`:
|
||
|
||
~~~
|
||
[php]
|
||
class m101129_185401_create_news_table extends CDbMigration
|
||
{
|
||
public function safeUp()
|
||
{
|
||
$this->createTable('tbl_news', array(
|
||
'id' => 'pk',
|
||
'title' => 'string NOT NULL',
|
||
'content' => 'text',
|
||
));
|
||
}
|
||
|
||
public function safeDown()
|
||
{
|
||
$this->dropTable('tbl_news');
|
||
}
|
||
}
|
||
~~~
|
||
|
||
Yii при применении миграции начнёт транзакцию, а затем выполнит код в
|
||
`safeUp()` или `safeDown()`. Если при этом возникнет какая-либо ошибка,
|
||
произойдёт откат транзакции, то есть база вернётся в начальное состояние.
|
||
|
||
> Note|Примечание: Не все СУБД полностью поддерживают транзакции и не для всех
|
||
> выражений. В том случае, если поддержки транзакций нет, реализовывать надо
|
||
> `up()` и `down()`. В случае использования MySQL некоторые выражения SQL могут вызвать
|
||
> [неявное применение транзакции](http://dev.mysql.com/doc/refman/5.1/en/implicit-commit.html).
|
||
|
||
|
||
Применение миграций
|
||
-------------------
|
||
|
||
Для того чтобы применить все новые миграции (то есть привести локальную БД в
|
||
актуальное состояние), следует запустить следующую команду:
|
||
|
||
~~~
|
||
yiic migrate
|
||
~~~
|
||
|
||
Команда покажет список всех новых миграций и, в случае утвердительного ответа,
|
||
по очереди запустит метод `up()` в каждом классе миграции в порядке их создания.
|
||
|
||
После применения миграции в таблицу `tbl_migration` будет внесена соответствующая
|
||
запись. Это позволяет узнать, какие миграции уже применены, а какие нет.
|
||
Если таблица `tbl_migration` не существует, она будет создана автоматически в
|
||
базе данных, указанной в компоненте `db` приложения.
|
||
|
||
Иногда требуется применить лишь одну или несколько новых миграций. Для этого можно
|
||
использовать следующую команду:
|
||
|
||
~~~
|
||
yiic migrate up 3
|
||
~~~
|
||
|
||
При этом применятся три новых миграции. Вместо трёх можно указать
|
||
любое количество применяемых миграций.
|
||
|
||
Также можно привести состояние базы данных к определённой версии:
|
||
|
||
~~~
|
||
yiic migrate to 101129_185401
|
||
~~~
|
||
|
||
В качестве параметра, указывающего версию, к которой надо привести базу данных,
|
||
используется часть имени файла, соответствующая времени создании миграции.
|
||
Если между последней применённой и указанной миграциями несколько миграций, то все
|
||
они будут применены. Если указанная миграция уже применялась, то будет произведён
|
||
откат всех миграций, применённых после неё (описано в следующем разделе).
|
||
|
||
|
||
Откат миграций
|
||
--------------
|
||
|
||
Для отката одной или нескольких последних применённых миграций можно
|
||
воспользоваться следующей командой:
|
||
|
||
~~~
|
||
yiic migrate down [step]
|
||
~~~
|
||
|
||
где необязательный параметр `step` задаёт количество миграций, которые надо откатить.
|
||
По умолчанию откатывается одна последняя применённая миграция.
|
||
|
||
Как было описано ранее, не все миграции можно откатить. При попытке отката таких
|
||
миграций будет выброшено исключение и процесс отката будет прерван.
|
||
|
||
|
||
Повторное применение миграций
|
||
-----------------------------
|
||
|
||
Повторное примение миграции производится путём последовательного отката и применения.
|
||
Осуществить это можно следующей командой:
|
||
|
||
~~~
|
||
yiic migrate redo [step]
|
||
~~~
|
||
|
||
где необязательный параметр `step` указывает количество миграций, которые необходимо
|
||
применить ещё раз. По умолчанию повторяется одна последняя миграция.
|
||
|
||
|
||
Просмотр информации о миграциях
|
||
-------------------------------
|
||
|
||
Кроме применения и отката миграций, инструмент миграций может отображать историю
|
||
миграций, а также новые, ещё не применённые миграции.
|
||
|
||
~~~
|
||
yiic migrate history [limit]
|
||
yiic migrate new [limit]
|
||
~~~
|
||
|
||
Здесь параметр `limit` указывает количество отображаемых миграций. Если `limit`
|
||
не указан, показываются все миграции.
|
||
|
||
Первая команда показывает уже применённые миграции, вторая — миграции, которые
|
||
ещё не были применены.
|
||
|
||
|
||
Изменение истории миграций
|
||
--------------------------
|
||
|
||
Иногда требуется изменить историю миграций так, чтобы текущая версия была
|
||
заменена на указанную без применения или отката миграций. Часто это требуется
|
||
при созданнии новой миграции. Для этого можно использовать следующую команду:
|
||
|
||
~~~
|
||
yiic migrate mark 101129_185401
|
||
~~~
|
||
|
||
Эта команда очень похожа на `yiic migrate to`, но она лишь изменяет таблицу истории
|
||
миграций до указанной версии без применения или отката самих миграций.
|
||
|
||
|
||
Настройка команды миграций
|
||
--------------------------
|
||
|
||
Есть несколько способов настроить команду миграций.
|
||
|
||
### Используя параметры командной строки
|
||
|
||
Команда миграций может быть настроена четыремя опциями:
|
||
|
||
* `interactive`: использовать ли интерактивный режим. По умолчанию true, то есть
|
||
при пременении миграции будет выводиться подтверждение. Если параметр выставлен
|
||
в false, то миграции можно применить в фоновом режиме.
|
||
|
||
* `migrationPath`: указывает директорию, в которой хранятся все файлы миграций.
|
||
Путь должен указываться в формате псевдонима, и соответствующая ему директория должна
|
||
существовать. Если параметр не указан, будет использована поддиректория
|
||
`migrations`, находящаяся внутри директории с приложением;
|
||
|
||
* `migrationTable`: указывает имя таблицы в базе данных, которая хранит историю
|
||
миграций. Значение по умолчанию равно `tbl_migration`. Структура таблицы следующая:
|
||
`version varchar(255) primary key, apply_time integer`;
|
||
|
||
* `connectionID`: указывает идентификатор компонента базы данных.
|
||
По умолчанию это 'db';
|
||
|
||
* `templateFile`: указывает путь к файлу, который используется как шаблон
|
||
для генерации классов миграций. Путь должен указываться как псевдоним
|
||
(то есть как `application.migrations.template`). Если путь не задан, будет
|
||
использоваться внутренний шаблон. В шаблоне токен `{ClassName}` будет заменён
|
||
именем класса миграции.
|
||
|
||
Для указания опций используется следующий формат:
|
||
|
||
~~~
|
||
yiic migrate up --option1=value1 --option2=value2 ...
|
||
~~~
|
||
|
||
К примеру, если необходимо мигрировать модуль `forum`, файлы миграций которого
|
||
расположены в директории модуля `migrations`, можно воспользоваться следующей командой:
|
||
|
||
~~~
|
||
yiic migrate up --migrationPath=ext.forum.migrations
|
||
~~~
|
||
|
||
|
||
### Глобальная конфигурация команды
|
||
|
||
В то время как опции командной строки позволяют нам на лету конфигурировать команду
|
||
миграций, иногда требуется применить настройки раз и навсегда. К примеру, нам
|
||
может понадобиться использовать другую таблицу для хранения истории миграций или
|
||
использовать свой шаблон миграции. Это можно сделать, изменив настройки консольного
|
||
приложения следующим образом:
|
||
|
||
~~~
|
||
[php]
|
||
return array(
|
||
......
|
||
'commandMap'=>array(
|
||
'migrate'=>array(
|
||
'class'=>'system.cli.commands.MigrateCommand',
|
||
'migrationPath'=>'application.migrations',
|
||
'migrationTable'=>'tbl_migration',
|
||
'connectionID'=>'db',
|
||
'templateFile'=>'application.migrations.template',
|
||
),
|
||
......
|
||
),
|
||
......
|
||
);
|
||
~~~
|
||
|
||
Теперь при запуске команды `migrate` указанные выше настройки будут применены
|
||
без ввода каких-либо дополнительных параметров. |