Ответ 1
Общий процесс
Мы создаем базовую линию для конкретной версии (например, v1.0
). Базовая линия включает в себя одно полное создание схемы script, а также обновление script из разрешенных предыдущих версий, если оно есть (более подробно об этом в данный момент). Итак, для v1.0
у нас будет только один script:
baseline-v1.0.sql
Из этой базовой линии мы создаем сценарии инкрементного изменения, когда мы работаем с предыдущей базой. Эти сценарии создаются таким образом, что они являются реентерабельными, так что их можно безопасно запускать несколько раз (когда первый раз выполняется только какая-либо фактическая работа, см. Следующий параграф о том, как это сделать). Мы просто создаем файл для каждого изменения script с базовым именем и меткой времени (которую мы называем версией). Так, например, скажем, мы создаем два сценария изменений после базовой линии. У нас были бы следующие файлы:
baseline-v1.0.sql (for creating new installations)
baseline-v1.0-201211071220.sql (created on Nov. 7, 2012 at 12:20 PM UTC)
baseline-v1.0-201211122019.sql (created on Nov. 12, 2012 at 8:00 PM UTC)
Мы создаем таблицу schema_version
, которая имеет два столбца: baseline
и version
. baseline
- это некоторая метка (например, v1.0
, упомянутая выше), а version
- это только метка времени, когда было создано изменение script (мы решили сделать это, потому что создание произвольных номеров версий создавало раздражающие административные издержки, где временная метка проста в использовании). Поэтому перед запуском изменения script, мы проверяем, было ли добавлено изменение script, запросив его на baseline
и version
. Если он уже присутствует, просто вернитесь из script или что-то еще. В противном случае примените изменение и вставьте в таблицу schema_version
, чтобы отметить завершенное изменение script.
Пример изменения script:
-- Created by <developer> on Nov. 7, 2012 at 12:20 PM UTC
declare @schema_baseline varchar(10), @schema_version varchar(12)
set @schema_baseline = 'v1.0'
set @schema_version = '201211071210'
if exists (select 1 from schema_version where baseline = @schema_baseline and version = @schema_version = @schema_version) return 0
-- begin change script
-- place your schema changes here
-- end change script
insert into schema_version(@schema_baseline, @schema_version)
Теперь, когда мы действительно устанавливаем программное обеспечение, мы запускаем соответствующий baseline
script. Когда мы обновляем эту версию, мы просто применяем сценарии изменений в порядке.
Когда мы достигнем важной вехи на этапе разработки продукта, мы создаем новую базовую линию. Итак, мы создаем новую базовую линию script (опять же, это снимок базы данных в качестве базовой линии) плюс обновление script от предыдущей базовой линии. Итак, скажем, у нас есть новая базовая линия, v2.0
, у нас были бы следующие файлы:
baseline-v2.0.sql (for creating new installations)
baseline-v2.0-upgrade-v1.0.sql (for upgrading from v1.0)
Затем процесс продолжается.
Как мы применяем изменения
Сценарии хранятся в исходном коде. У нас есть инструмент, который упаковывает эти файлы и автоматически обновляет базы данных, которые используют наши команды поддержки и установки. Инструмент вычисляет текущую базовую базу целевой базы данных и запрашивает у пользователя, хочет ли он перейти на базовую линию в пакете. Если это так, и существует действующий путь обновления из текущей версии, он применяет обновление script и обновляет schema_version.baseline
и удаляет все записи для сценариев изменений из предыдущей базовой линии. Если база данных новая, она применяет регулярную базовую линию script. В любом случае, после достижения базовой линии, он применяет все сценарии изменений от базовой линии, которые присутствуют в пакете, по одному за раз, в порядке, в транзакции. Если конкретное изменение script завершается с ошибкой, оно откатывает последний набор изменений и ошибок. Мы смотрим на журнал, исправляем любые проблемы, а затем снова запускаем пакет. В этот момент он должен просто подобрать последнее изменение script, которое преуспело, экономя время.
Инструменты автоматизации и Diff
Мы не позволяем инструментам diff напрямую обновлять производственные базы данных. Это слишком рискованно. Разумеется, мы используем инструменты для разметки, чтобы помочь создать сценарии обновления и изменения, но как только мы их получим, мы их расчесываем, массируем, тестируем и т.д., Затем создаем обновление или изменяем script в соответствии с выше. Мы используем скрипты tools/shell для создания файлов изменений script и устанавливаем проверку плиты котла schema_version
.
Предостережение
Это на самом деле довольно прямолинейно, и он работает хорошо. Единственный раз, когда это действительно сложно, с ветвями. По большей части, ветки обрабатываются хорошо. Если нам понадобится изменение script для конкретной работы ветки, он будет очень быстро складываться в магистрали, как только мы снова объединим ветку. Нет проблем. Там, где это сложно, когда две ветки пытаются делать подобные вещи или где одна ветка полагается на другую. Тем не менее, это проблема процесса и планирования. Если мы застряли в такой ситуации, мы просто создадим новую базовую линию (скажем v2.1
), а затем обновим ветки соответственно.
Еще одна вещь, о которой стоит помнить, - это то, что если установка хочет быть обновлена с одной базовой линии на другую, она должна применить все выдающиеся изменения для текущей базовой линии, прежде чем мы перейдем на новую. Другими словами, мы не позволяем установкам прыгать прямо от того места, где они находятся, к следующей базовой линии (если, конечно, они не находятся в самой последней версии для текущей базовой линии).