Миграция базы данных в сложной ветвящейся системе - PullRequest
31 голосов
/ 20 июня 2011

В нашем текущем рабочем процессе разработки мы ввели миграцию базы данных (используя Ruckusing ), чтобы синхронизировать схемы БД наших разработчиков. Он отлично работает, довольно прост в использовании, но теперь мы перешли на git как VCS и столкнулись со следующей проблемой в нашей системе управления версиями базы данных.

При проверке ветки, которая находилась в разработке в течение некоторого времени, может случиться так, что схема базы данных значительно отклонится от схемы в ветви, из которой я иду. Это вызывает конфликты базы данных в некоторых случаях. Логически кажется, что нам нужно запустить миграцию в зависимости от ветви, в которой мы были ранее, но это может очень быстро усложнить задачу и наверняка столкнется с проблемами у некоторых людей. И, насколько я знаю, не существует системы переноса БД, которая бы учитывала ветви ??

Дополнительная сложность возникает при переходе к ветви функций, в которой нам может понадобиться запустить некоторые миграции, в то время как другие - нет ... технически это кажется невозможным при использовании наших текущих сценариев dbmigration, есть ли какие-нибудь разумные альтернативы? Есть ли предпочтительные способы работы с миграциями баз данных в очень активной и разветвленной системе разработки?

Ответы [ 5 ]

28 голосов
/ 20 июня 2011

Я бы не согласился с тем, что постепенные миграции являются гнилыми.На мой взгляд, наличие набора собственных сценариев было бы более плохим подходом, чем наличие реального инструмента для такой работы, который облегчит отслеживание этих изменений.Раньше мне приходилось сталкиваться с подобной ситуацией, поэтому, надеюсь, я смогу поделиться некоторыми идеями.

По моему опыту, RDBMS-схемы и ветви не очень хорошо сочетаются.В зависимости от вашего ветвления схемы должны быть, по крайней мере, несколько похожими, и в этом случае миграции не должны сильно отличаться.Или я мог просто неправильно понять всю проблему.Если вы, например, пытаетесь сохранить специфичный для клиента код в ветке, то, возможно, вам следует подумать о способе его модульности.Мы сделали что-то вроде этого, имея правила, которые утверждали, что специфическая для клиента схема меняется, и код может зависеть только от общей базы кода, а не наоборот.Мы также установили приоритет между сменами модулей на основе модуля и даты, поэтому мы в большинстве случаев знали порядок, в котором должны были применяться изменения.YMMV, конечно, но сложно дать конкретику, не зная ваших текущих настроек.

В моей старой компании мы успешно использовали инструмент под названием Liquibase , который звучит похоже на то, что вы используете.По сути, это инструмент для перевода схемы БД и всех данных из одного известного состояния в другое известное состояние.Тот же набор изменений применяется только один раз, поскольку liquibase ведет журнал изменений с контрольными суммами.Журналы изменений написаны в определенном формате XML.Я настоятельно рекомендую попробовать, если вам нужны альтернативы.

В любом случае, способ, которым мы обрабатывали код клиента и ветви, заключался в том, чтобы иметь конкретную базу данных / схему для данной ветви.Таким образом, вы можете получить схему и данные из точки ветвления и только перенести diff в текущую ситуацию.Мы не отменили изменения, даже если теоретически жидкость-база могла бы поддержать это, поскольку мы чувствовали, что это слишком громоздко и подвержено ошибкам.Принимая во внимание, что liquibase сохраняет свое собственное состояние, миграция всегда была такой же простой, как принятие текущего состояния в данной ветви и применение всего.Были применены только новые наборы изменений, в результате чего схема была в хорошем состоянии.

Мы использовали mercurial , который распространяется, как git, поэтому настройка была довольно схожей.У нас также были локальные базы данных для разработчиков на ноутбуках dev и ряд сред, как для разных заказчиков, так и для разных этапов (разработка, интеграция, производство), поэтому модель была подвергнута реальному тестированию, и она работала на удивление хорошо.У нас были некоторые конфликты в наборах изменений, но мы в основном смогли разрешить их вскоре после появления проблемы.Локальные envs разработки были действительно самой сложной частью, так как во время разработки, возможно, были внесены некоторые изменения схемы, которые не всегда были совместимы с более поздними наборами изменений, но структурированный характер изменений и наличие известного состояния, к которому можно вернуться, приводят к очень немногимреальные проблемы.

При таком подходе есть несколько предостережений:

  1. Все и любые изменения схемы должны быть реализованы в наборах изменений.Самой большой причиной растерянности всегда было то, что кто-то немного возился.
  2. Первый пункт также применим, даже если вы используете инструмент, который изменяет схему, например, ORM-инструмент, такой как Hibernate .Вы должны быть довольно близки с этим инструментом, чтобы понимать изменения, которые он вносит и требует.
  3. Все пользователи должны купить это и научиться следовать правилам.Проверка 1.
  4. Наступает момент, когда миграция лотов наборов изменений начинает занимать слишком много времени.В это время вам нужно будет создать новую базовую линию, которая может быть немного хитрой, особенно с большим количеством ветвей.Также хорошо планировать заранее и, по крайней мере, знать обо всех существующих ветвях БД.
  5. Вам нужно немного спланировать заранее с ветвями, чтобы знать, собираются ли они в какой-то момент вернуться обратно к мастеру.Наивное объединение может не сработать для изменений схемы.
  6. Для очень долгоживущих ветвей и отдельных наборов данных эта модель может быть недостаточно сильной

Суть, однако, в том, что чем больше у вас структуры и контроля над базой данных, тем легчемиграции будут.Поэтому такие инструменты, как Liquibase , могут быть очень ценным активом, чтобы помочь вам отслеживать эти изменения.Это относится к более сложным моделям даже в большей степени, чем к простым, поэтому, по крайней мере, не думайте о сбросе всех инструментов, которые у вас уже есть.И найдите время, чтобы изучить другие альтернативные инструменты.

Некоторая структура и управление лучше, чем ничего, или даже хуже, думая, что вы контролируете большую кучу ручных скриптов.

15 голосов
/ 20 июня 2011

Я думаю, что сама идея постепенных миграций довольно гнилая, правда. В такой сложной среде, как ваша, это действительно не работает. Вы могли бы заставить это работать для простых шаблонов ветвления, но для чего-то сложного, это будет кошмар.

Система, с которой я сейчас работаю, использует другой подход: у нас нет возможности делать постепенные миграции, а только перестраивать базу данных с базового уровня. Во время первоначальной разработки эта базовая линия была пустой базой данных, а во время обслуживания - копия действующей базы данных (восстановленная из дампа). У нас просто есть куча сценариев SQL и XML, которые мы применяем к базовой линии, чтобы получить текущую систему (по сути, миграции, но не предназначенные для поэтапного запуска). Обновление или переключение веток тогда очень просто: сбросьте базу данных, загрузите дамп, чтобы установить базовый уровень, запустите сценарии.

Этот процесс не такой быстрый, как выполнение нескольких миграций, но он достаточно быстрый. Это займет достаточно много времени, чтобы вы могли пойти и принести чашку кофе, но не достаточно долго, чтобы получить обед.

Огромным преимуществом является то, что начало с нуля базы данных означает, что процесс полностью независим от истории, поэтому ему не нужно знать или заботиться о пересечении ветвей, возвращении во времени или чем-то еще.

Когда вы запускаете релиз вживую, вы, очевидно, делаете вещи немного по-другому: вы не уничтожаете базу данных и не загружаете дамп, потому что система уже находится на базовом уровне (базовый уровень определяется как состояние работающей системы! ). Вы просто запускаете сценарии. И после этого создайте новый дамп, который будет использоваться в качестве нового базового уровня для разработки.

2 голосов
/ 21 ноября 2015

Я нахожусь в аналогичной ситуации, когда я работаю над живым веб-сайтом и несколькими ветками разработки, в которых мне нужно изменить схему базы данных.

Я решил это, написав post-checkout и ловушку post-merge, которые можно красиво использовать с git. Я храню все свои миграции в виде файлов SQL в отдельном каталоге и фиксирую их вместе с измененным кодом PHP. Каждый раз, когда я выполняю

git checkout

или

git merge

git автоматически вызовет соответствующую миграцию вверх и вниз. Смотрите мою реализацию на Github .

В качестве специального запроса (для тех из вас, кто не хочет переходить по ссылке на github) еще несколько объяснений:

Рассмотрим следующий сценарий. У вас есть две ветви:

  • master - содержит веб-сайт, который в данный момент онлайн
  • функция - которая содержит незавершенную новую функцию

Чтобы новая функция работала правильно, необходимо изменить схему базы данных. Рабочий процесс выглядит следующим образом:

  1. Когда в своей ветке вы изменяете свой код, который требует изменения Схема базы данных, вы также фиксируете два новых файла SQL в каталоге миграции, говорят:

    • 20151120130200-extra-field-up.sql (содержит все SQL-запросы для переноса вверх)
    • 20151120130200-extra-field-down.sql (связывается со всеми SQL-запросами для переноса вниз)
  2. Когда вы сейчас выполняете проверку для мастера, git-ловушка после получения будет:
    1. найти все * -down.sql скрипты в коммитах от <new HEAD>..<old HEAD>
    2. выполнить эти сценарии с локальной базой данных
    3. найти все * -up.sql скрипты в коммитах с <old HEAD>..<new HEAD>
    4. выполнить эти сценарии с локальной базой данных
  3. Когда вы объединяете свою ветвь объектов в master, ловушка после слияния будет:
    1. найти все * -up.sql скрипты в коммитах от master..feature
    2. выполнить эти сценарии с локальной базой данных

Установить

Просто скопируйте файл post-checkout и / или post-merge в .git / hooks каталог вашего собственного репозитория git. Вы можете редактировать раздел конфигурации этих файлы. См сами файлы для объяснения.

Использование

Имена файлов миграции SQL имеют решающее значение. Они должны заканчиваться up.sql или down.sql. Остальная часть названия полностью зависит от вас. Тем не менее, если у вас есть один коммит с несколькими up-миграциями и / или несколькими нисходящие миграции, порядок, в котором они выполняются, зависит от лексикографический порядок. Миграционные файлы, которые находятся в разных коммитах, будут всегда вызываться в том же (обратном) порядке, что и коммиты.

Не требуется, чтобы у вас были как повышающая, так и понижающая модернизация, и при этом это не требование, чтобы восходящие и нисходящие миграции были названы одинаковыми.

1 голос
/ 01 марта 2013

Подход, который я подумываю о тестировании в нашем текущем проекте, заключается в создании ветки 'миграций', и все (и только) миграции выполняются в этой ветке.Разработчики должны объединиться из этой ветви в свою текущую ветку перед созданием миграции, чтобы их миграция всегда создавалась поверх последней миграции.Все проекты объединяются из этой ветви, поэтому каждая ветвь имеет концепцию истории линейной миграции.Это дает каждой ветви возможность перемещаться между версиями базы данных.При переключении на ветку, которая зависит от другой версии базы данных, разработчик применяет любую подходящую миграцию.

Раздражение (помимо дополнительной работы и усердия в переносе миграции в специальную ветку) запоминает, какая миграциясоответствует определенной отрасли.Я предполагаю, что один из способов сделать это - вместо того, чтобы совершать миграции непосредственно в ветку миграций, фиксировать миграцию (и только миграцию) в текущую ветвь, а затем выбирать вишню, которая фиксирует ветку миграции.Затем вы можете просто посмотреть в последний раз текущую ветку, выбранную вишней, на ветку миграции и узнать, что эта разность содержит необходимую миграцию.Я думаю, что это было бы возможно.Кроме того, разработчик может создать миграцию, чтобы посмотреть, какие изменения потребуются, а затем попытаться определить, какую миграцию целесообразно использовать.

Извините за смутное предложение;если мы в конце концов попробуем этот подход, я отредактирую это предложение с более конкретными рекомендациями.

0 голосов
/ 15 августа 2012

Это то, над чем я работал в последнее время. Для меня проблема не в том, что схема базы данных сама по себе разошлась, а, скорее, git не может объединить их вместе. Ветви объектов, которые касаются схемы базы данных, всегда пугают.

Решение, о котором я думал, состоит в том, что вместо линейных миграций, есть миграции, которые зависят от других миграций. Вы получаете хороший график зависимости ваших миграций, который достаточно легко линеаризовать (топологическая сортировка). Просто следите за именованными миграциями в вашей базе данных и в правильном порядке выполните обновления, которые еще не были обновлены.

Например, addCustomerSalt зависит от initialSchema, а separateAddress зависит от person.

Единственная проблема, которую это не решает, заключается в том, что если ветвь A зависит от обновления Z, созданного в ветке B, но, может быть, в этом случае вам следует перейти к общему предку?

...