Что такое миграции и зачем они нужны?
Если Вы уже знаете, что такое миграции и зачем они нужны, но не знаете как с ними работать, то переходите к инструкции. Если у Вас еще нет представления о миграциях, то перед инструкцией почитайте пару абзацев.
Давайте представим, что над проектом работает 3 программиста. Каждый из них делает свою часть работы в процессе меняя и дописывая код, выгружает его в систему контроля версий. В процессе изменения исходного кода приложения меняется и структура базы данных. Добавляются новые таблицы и поля, лишнее удаляется и т.д.. Для того что бы отследить изменения в структуре БД, программисты договорились складывать все SQL запросы изменения БД в файл, имеющий имя текущей даты, в одну папку. Теперь у всех при пуле есть последняя версия исходного кода и список файлов с изменениями структуры БД. Перед продолжением работы, что бы не было ошибок, программисту необходимо выполнить все запросы из новых файлов и только после этого продолжить работу. Тим лид (он же главный) при деплое проекта не только будет копировать файлы на боевой сервер, но и импортировать все запросы по изменению структуры БД. Не слишком удобно, правда? Таких подходов с отслеживанием структуры БД есть много вариаций, я описал один из возможных.
Отслеживание изменения структуры базы данных и есть миграции. Каждая миграция - это новая версия БД. Т.е. в нашем случае миграция - обновление структуры базы данных от одной версии к другой.
В Yii реализована поддержка миграций, позволяющая применять изменения в структуре и отменять их.Управление миграциями в Yii осуществляется с помощью консольной команды yiic migrate
. Она отвечает за создание, применение, откат, повторное применение и просмотр истории миграций.
Для начала необходимо проверить настройки соединения с
базой данных в файле protected/config/console.php
.
<?php //... 'db' => array( 'connectionString' => 'mysql:host=localhost;dbname=main', 'emulatePrepare' => true, 'username' => 'root', 'password' => '', 'charset' => 'utf8', 'enableProfiling' => true, ), //...
Проверьте существование директории protected/migrations
и доступна ли она для записи.
Открываем консоль (для Windows Win + R и введите cmd).
Далее переходим в папку проекта
(к примеру: D:/web/home/site.local/www
) в директорию protected
:
d: cd /web/home/site.local/www/protected
Создаем миграцию
yiic migrate create [migrate_name]
[migrate_name]
- это обязательный параметр,
который должен содержать краткое описание миграции
(например, create_comments_table). Этот параметр будет использоваться как часть
имени класса миграции (в имени можно использовать буквы, цифры и нижнее
подчеркивание).
Пример создания миграции, для новой таблицы комментариев:
yiic migrate create create_comments_table
При выполнении этой команды будет создан файл:
m150108_091710_create_comments_table.php
в папке
protected/migrations
, который будет содержать следующий код:
<?php class m150108_091710_create_comments_table extends CDbMigration { public function up() { } public function down() { echo "m150108_091710_create_comments_table does not support migration down.\n"; return false; } /* // Используйте safeUp/safeDown для использования транзакций public function safeUp() { } public function safeDown() { } */ }
Имя файла и класса строится по шаблону: m[timestamp]_[migrate_name]
, где [timestamp] - это время создания миграции в формате yymmdd_hhmmss, а [migrate_name]
- это имя указанное в параметре команды.
Рассмотрим методы класса подробнее:
Метод up()
должен содержать код, который выполняет миграцию (добавление таблиц, полей, переименование таблиц, полей и т.д.).
Метод down()
может содержать код, который будет выполнять
отмену команд, выполненную в методе up()
(откат структуры БД к предыдущей версии). Случается так,
что реализовать откат в методе down() нельзя. Например при удалении данных из
таблицы, вернуть их нет возможности.
В таких случаях миграция считается необратимой, т.е. невозможно вернуть
БД к предыдущему состоянию. В генерируемом Yii примере, метод down()
возвращает false, т.е. откат миграции невозможен.
up()
или метод down()
возвращают false
,
все последующие миграции не будут применены.
В версии 1.1.6 для отмены последующих миграций необходимо выдать исключение.
Для примера рассмотрим создание таблицы комментариев.
<?php class m150108_091710_create_comments_table extends CDbMigration { public function up() { $this->createTable('comments', array( 'id' => 'pk', 'name' => 'string NOT NULL', 'text' => 'text', )); } public function down() { $this->dropTable('comments'); } }
Список команд для работы с миграциями можете посмотреть здесь:
http://www.yiiframework.com/doc/api/1.1/CDbMigration
Если у Вас возникают сложности при написание запросов с помощью: createTable
,
addColumn
, dropColumn
, dropTable
, renameColumn
, renameTable
и т.д.. Можете использовать
прямые SQL запросы Yii::app()->db->createCommand
. Пример:
<?php class m150108_091710_create_comments_table extends CDbMigration { public function up() { $sql = "CREATE TABLE IF NOT EXISTS `comments` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(255) NOT NULL, `text` TEXT, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;"; Yii::app()->db->createCommand($sql)->execute(); } public function down() { $sql = "DROP TABLE comments"; Yii::app()->db->createCommand($sql)->execute(); } }
Применение миграций
yiic migrate
Данная команда выводит список всех новых миграций и вопрос применить ли миграции:
Yii Migration Tool v1.0 (based on Yii v1.1.15) Creating migration history table "comments" ...done/ Total 1 new migrations to be applied: m150108_091710_create_news_table Apply the above migrations& (yes:no) [no]:
При положительном ответе, команда запустит по очереди метод
up()
в каждом из классов миграции в порядке их создания
(в данном случае это 1 миграция).
После выполнения команды миграции будет создана таблица
tbl_migration
, если она еще не создана
(таблица будет находиться в основной БД указанной в конфигурации db
).
В эту таблицу будет внесена запись, которая позволяет узнать, какие миграции
уже применены, а какие нет.
Бывают ситуации в которых необходимо применить одну или несколько новых миграций. Для этого нужно использовать команду:
yiic migrate up [count]
Эта команда выполнит [count] новых миграции. [count] - любое количество применяемых миграций.
Если Вам необходимо привести БД в определенное состояние (версию), то можно использовать следующую команду:
yiic migrate to [version]
[version] - версия к которой необходимо привести базу данных, здесь используется часть имени файла, которая соответствует времени создания миграции (например: 101129_185401). Если указанная миграция уже применена, то будет произведён откат до этой миграции.
Транзакции в миграции
Для сложных миграций с использованием транзакций можно использовать встроенный механизм транзакции явно:
<?php class m150108_091710_create_comments_table extends CDbMigration { public function up() { $transaction=$this->getDbConnection()->beginTransaction(); try { $this->createTable('comments', array( 'id' => 'pk', 'name' => 'string NOT NULL', 'text' => 'text', )); $transaction->commit(); } catch(Exception $e) { echo "Exception: ".$e->getMessage()."\n"; $transaction->rollback(); return false; } } //... }
Или использовать механизм встроенный в миграции.
Для этого вместо метода up()
нужно использовать
safeUp()
и вместо метода down()
используйте safeDown()
:
<?php class m150108_091710_create_comments_table extends CDbMigration { public function safeUp() { $this->createTable('comments', array( 'id' => 'pk', 'name' => 'string NOT NULL', 'text' => 'text', )); } public function safeDown() { $this->dropTable('comments'); } }
При выполнении миграции, Yii начнёт транзакцию и выполнит метод safeUp()
или метод safeDown()
. Если произойдет ошибка,
сработает откат транзакции и БД вернется к состоянию до начала миграции.
Отмена миграций
Если Вам необходимо отменить миграцию или несколько последних миграций, то можно воспользоваться следующей командой:
yiic migrate down [step]
[step]
- необязательный параметр, который задает количество
отменяемых миграций. Если параметр не указан, то отменяется одна
последняя миграция.
Если миграцию невозможно откатить, то будет отдано исключение и откат будет прерван.
Повторное применение миграций
Если во время выполнения миграции возникли какие-то проблемы, можно повторно применить миграцию. Это делается с помощью следующей команды:
yiic migrate redo [step]
[step]
- необязательный параметр, который задает количество
миграций, которые необходимо применить еще раз.
Если параметр не указан, то повторно применяется одна последняя миграция.
Просмотр информации о миграциях
Для просмотра истории миграций которые уже применены или еще не применены, есть следующие команды:
yiic migrate history [limit] yiic migrate new [limit]
[limit]
- количество отображаемых миграций.
Если этот параметр не указан, то будут показаны все миграции.
history
- покажет примененные миграции.
new
— список новых миграций, которые еще не применены.
Изменение истории миграций
Если Вам требуется применить миграцию без откатов или применений других миграций, то можно воспользоваться следующей командой:
yiic migrate mark [version]
Команда mark
похожа на to
, с тем отличием,
что mark
изменит таблицу tbl_migration
до указанной версии без применения или отката миграций.
Все, теперь Вы можете попрактиковаться в применении миграций в Yii Framework и существенно облегчить отслеживание изменений структуры базы данных при работе в команде. Удачи!
console.php
в зависимости от места запуска читайте здесь:кодер.укр/записи/yii_framework_настройка_конфигурации_console_php_для_локальной_разработки_и_для_сервера
Комментарии
Спасибо за статью!
ОтветитьУ меня есть вопрос. Я сделал 2 варианта настроек console.php и в зависимости от места запуска подключается один из них. На компьютере все отлично работает, но когда заливаю все на сервер и пробую выполнить команду на сервере yiic migrate, то выводит ошибку:
-bash: yiic: command not found
В чем может быть проблема?
Попробуйте написать так:
Ответитьphp yiic migrate
Теперь пишет:
Ответитьexception 'CDbException' with message 'CDbConnection failed to open the DB connection: SQLSTATE[28000] [1045] Access denied for user .......
Все разобрался, после использования php yiic migrate, все заработало. Вторая ошибка была из-за неправильно настроенного подключения к базе в console.php для сервера. Еще раз спасибо!
ОтветитьПодскажите пожалуйста, что не так. У меня выдает ошибку при выполнении команды yiic migrate create test:
Ответить"php" не является внутренней или внешней командой, исполняемой программой или пакетный файлом.
Скорее всего у Вас не добавлен PHP в переменные среды. Как это сделать можете посмотреть здесь:
Ответитькодер.укр/записи/windows_и_denwer_добавление_php_в_переменные_среды
я делал так: Z:/usr/local/php5/php.exe yiic migrate create new_table_from_test
ОтветитьОбъяснилте мне пожалуйста, ninja писал о двух файлах конфигурации console.php для пк и для сервера. Я не понял как это реализовать? Или при загрузке кода на сервер нужно менять настройки в console.php для сервера? Но это как то неудобно.
ОтветитьНе учел этот момент в статье. В комментарии много писать, поэтому написал отдельную статью:) Читайте здесь:
Ответитькодер.укр/записи/yii_framework_настройка_конфигурации_console_php_для_локальной_разработки_и_для_сервера
Отлично, все работает! Спасибо за статью.
ОтветитьОтличное дополнение, мне тоже пригодилось
ОтветитьХорошая статья, без лишней воды, все по теме. А главное все работает без шаманства и поиска по другим сайтам, спасибо, добавил в закладки
ОтветитьА можно использовать в миграциях модели? Наподобие:
Ответить$model = new News();
$model->name = '...';
...
$model->save();
Так можно?
Да, можно. Но лучше что-бы миграции жили отдельно, а основной код отдельно. Это делается для того что-бы при изменениях в модели миграции все равно работали, т.к. править существующею миграции - плохо. А то можно так доработать модель что старая миграция перестанет исполняться и отдавать ошибку.
ОтветитьЕсли использовать систему контроля версий, то при возникновении ошибки можно откатиться до версии когда модель не правилась, выполнить миграцию до определенной версии. Далее перейти на текущую версию кода и выполнить миграцию до текущей версии структуры бд
ОтветитьМожно конечно, но это как то слишком усложнено. Лучше делать без моделей
ОтветитьТо есть если я правильно понял, то все изменения в БД надо делать через миграции, а потом их применять? И в самой базе вручную ничего не менять?
ОтветитьЕсли я хочу добавить новую таблицу, то я создают пхп файл миграции, пишу там запрос на создание таблицы. Потом применяю миграцию, так?
Да, все верно
ОтветитьЯ делаю и так и так. Т.е. в зависимости от ситуации, могу добавить миграцию, а потом выполнить ее, а могу добавить поле руками и вставить запрос в миграцию. Проблем пока не возникало.
ОтветитьЯсно, спасибо
ОтветитьПомогите, ввожу в консоль:
Ответитьyiic migrate create my_migrate
и получаю ошибку: 'yiic' is not recognized as an internal or external command, operable program or batch file.
Что я делаю не так?
Вы выполняете команду yiic migrate create my_migrate в папке protected своего проекта? Если нет, то перейдите в нее (z:/home/myproject.local/www/protected)
ОтветитьСпасибо, не зашел в папку protected
ОтветитьЗдравствуйте, а можно в миграцию добавить sql дамп, файл экпорта БД из phpMyAdmin. Чтобы сразу выполнить стартовую миграцию с созданием таблиц и наполнением их данными
ОтветитьА как пропустить определенное количество миграций?
ОтветитьДля этого используйте команду:
Например:
Получим список невыполненных миграций, например:
---
m160921_123540_add_...
m160921_171354_add_...
m160922_091451_add_...
m170113_191621_add_...
m170116_151225_add_...
m170626_132837_add_...
---
Указываем что миграции до m170626_132837_add_... ненужно применять
При выполнении команды
Будет применена миграция m170626_132837_add_... и следующиеОтветить
Спасибо
Ответить