Как стать автором
Обновить

Комментарии 27

Большое спасибо, как раз собирался разобраться с миграциями
Спасибо за столь своевременную для меня статью. как раз раздумывал как бы правильно базу вести.
Тогда у нас получится ситуация, когда часть изменений будет сделана, а часть нет.

А разве транзакции не решают эту проблему?
Нет. Я не уверен, надо посмотреть исходники, но доктрина оборачивает миграцию в транзакцию и это не спасает. Еще я не знаю дружат ли ALTER и CREATE TABLE с транзакциями. Надо порыться в доке к БД. Или может кто подскажет?
Как правило, не дружат. Исключение — вроде как только MS SQL Server (и то с оговорками)
PostgreSQL — при откате транзакций откатываются в том числе и изменения структуры данных:

CREATE TABLE:
postgres=# begin;
BEGIN
postgres=# create table test(id serial, name varchar);
NOTICE: CREATE TABLE will create implicit sequence «test_id_seq» for serial column «test.id»
CREATE TABLE
postgres=# insert into test(name) values('foo');
INSERT 0 1
postgres=# insert into test(name) values('bar');
INSERT 0 1
postgres=# select * from test;
id | name
----+------
1 | foo
2 | bar
(2 rows)

postgres=# rollback;
ROLLBACK
postgres=# select * from test;
ERROR: relation «test» does not exist

DROP COLUMN:
postgres=# create table test(id serial, name varchar);
NOTICE: CREATE TABLE will create implicit sequence «test_id_seq» for serial column «test.id»
CREATE TABLE
postgres=# begin;
BEGIN
postgres=# alter table test drop column name;
ALTER TABLE
postgres=# select * from test;
id
— (0 rows)

postgres=# rollback;
ROLLBACK
postgres=# select * from test;
id | name
----+------
(0 rows)


Что я делаю не так?
изменения DDL транзакциями не защищаются. По крайней мере в Oracle так было.
Ну на оракле свет клином не сошелся. Транзакционность DDL поддерживается в PostgreSQL, SQL Server, Sybase Adaptive Server, DB2 UDB, Informix, Firebird. Пруфлинк
Получается, что из известных СУБД только MySQL (Oracle в 11g Release 2 вроде влепили костыль, который частично это реализует) не поддерживает откат DDL, чем я, в общем-то, и не удивлен.
Честно говоря, не понимаю одного в миграциях symfony:

1. У нас есть schema.yml для текущей структуры. Сделали build, работаем. schema.yml сохранилась в schema1.yml (к примеру)
2. Мы поменяли schema.yml, добавив пару полей. Сделали build. Зачем нужно ручками что-то писать? Неужели невозможно посчитать разницу между schema'ами, создать автоматически файл с миграцией и при build'е его запустить. Аналогично с rollback. Внутри можно делать как угодно — хоть на каждую правку атомарное действие, которое можно отключить.

Ей Богу, проще ручками в базе поправить, полученный SQL-код записать в отдельный sql-файл и, при случае, использовать. Меньше проблем, меньше времени, ничего не надо изучать.
см. symfony doctrine:generate-migrations-diff

> Ей Богу, проще ручками в базе поправить, полученный SQL-код записать в отдельный sql-файл и, при случае, использовать. Меньше проблем, меньше времени, ничего не надо изучать.

Я про то и писал, что на определенном уровне разработке это намного сложнее, чем использовать миграции.
На самом деле, я сужу с позиции Active Record из rails. Там даже в больших проектах миграции используются без особых проблем. Doctrine, скажем политкорректно, очень напоминает Active Record. Зачем изобретать свой велосипед, когда есть готовое и уже проверенное временем решение.
Ну и здесь используются без проблем. В чем суть спора?
Нет-нет, я ничуть не спорю, а пытаюсь понять возникший когнитивный диссонанс (сам использую propel и радуюсь жизни):

1. Вы пишите, что при миграции c версии k на версию n могут возникнуть проблемы из-за *** (подставить нужное).
2. Один из моих знакомых — очень хороший разработчик на ruby on rails. Он такие вещи делает постоянно и без сложностей.
3. Я сходу не вижу особых сложностей в текущей структуре symfony для реализации механизма миграций.
Это уже недостатки текущей реализации. Единственную сложность, которую я вижу, это невозможность автоматом откатить сложную миграцию, если она упала.
А ваш товарищ, наверное, пришет атомарные миграции.
Все остальное есть куда допиливать, если еще не допилили во второй доктрине.
Гм, а почему бы не сделать достаточно простой механизм «разбиения» сложной миграции на атомарные. Условно говоря: разработчик делает, как обычно, пишет большую миграцию. При вызове консольной команды doctrine разбивает её на несколько атомарных (например, ревизия 5, подмиграции 5.1, 5.2 и т.п.). Тогда часть проблем решится.
Теоретически можно, если еще опустить вопросы очередности выполения, и сложных/множества запросов для data migration. А как тогда быть с номером версии БД. Может получится так, что написали одну миграцию, а номер скакнул на 10. А не скакать нельзя — это ролбек. Да и с ролбеком будут проблемы.
Нет, плохая идея.
Это на совести разработчика и мануала с best practice
С номером версии всё достаточно просто. Мажорные версии — миграции. Минорные версии внутри мажорной — атомарные миграции.

Очерёдность — тоже не проблема. Можно её поставить такой же, какой она бы была в «большой» миграции.

Схема, по-моему, достаточно проста:
Резивия 5: дописали 3 изменения в миграцию. Хотим мигрировать. Что делает doctrine:

1. Создаёт миграцию с 5 на 6.
2. Создаёт 3 атомарные миграции 5.1, 5.2, 5.3.
3. Если нет никаких дополнительных опций, делает полную миграцию.
4. Если, например, 5.2 не выполнилась, делает rollback 5.1 и пишет ошибку: «в миграции 5.2 ошибка». Так, кстати, сходу можно будет понять, где собака зарыта.
5. Можно указать дополнительные опции: например, не делать миграцию 5.2. Тогда doctrine запишет к себе, что 5.2 сделана не была. При rollback'е, естественно, это будет учитываться.
6. Выполнить атомарную миграцию отдельно невозможно. Только с одной мажорной ревизии на другую.

ИМХО, такая последовательность решает указанные Вами проблемы.
Лучшее — враг хорошего. Это как раз такой случай.
Лучше оставить систему очень простой и дописать соглашение, чем неоправданно усложнять и возможно получить новые грабли.
1. делаешь изменения в схеме
2. symfony doctrine:generate-migrations-diff
3. symfony doctrine:migrate
4. symfony doctrine:build --all-classes
5. symfony cc
Но, насколько я понял, подобный метод не делает rollback с произвольной ревизии БД на произвольную?
Вы про symfony doctrine:migrate номер_версии?
Честно говоря, не слышал про номер версии. Знаю, что есть symfony doctrine:migrate --down и symfony doctrine:migrate --up. Вопрос в том: в начале проекта у меня, например, была исходная база данных (ревизия 1). Работали, работали, получили ревизию, например, 50. Но тут что-то пошло не так, откатили к 30. Затем всё-таки решили часть оставить, донакатили до 40. Вопрос: можно ли не опасаясь проблем так сделать?
Технически — легко.
Вы издеваетесь или принципиально не читаете symfony help doctrine:migrate?
Я честно говорил, что не использую doctrine, а использую propel. Прочитал мельком при выходе symfony 1.3/1.4 пункт про doctrine integration. Поэтому и интересуюсь.
Даже только ради этой одной фичи стоит использовать Doctrine.

И да: symfony doctrine:build --all-classess --and-migrate
>>Почему? Если мы написали одну большую миграцию (таблицы, ключи, правки данных), и она у нас вдруг падает (а это легко, например создание FK на ключах с разными интами в унаследованной БД или создание FK, когда нарушена ссылочная целостность). Тогда у нас получится ситуация, когда часть изменений будет сделана, а часть нет. Какая именно часть — надо искать.

Не знаю как в Symfony, но в Rails миграции делаются в транзакциях.
Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.