Подтвердить что ты не робот

Переходы базы данных в сложной ветвящейся системе

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

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

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

4b9b3361

Ответ 1

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

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

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

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

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

Ответ 2

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

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

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

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

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

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

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

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

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

Ответ 3

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

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

git checkout

или

git merge

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

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

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

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

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

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

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

Установка

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

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

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

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

Ответ 4

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

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

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

Ответ 5

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

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

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

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