Автоматизация для программистов: Автоматизированная миграция баз данных

Использование LiquiBase для внесений изменений в базы данных

Часто базы данных теряют синхронизацию с приложениями, для которых они разрабатываются. Приведение базы данных к требуемому состоянию может потребовать значительных усилий. В этой статье из цикла Автоматизация для программистов эксперт по автоматизации Поль Дюваль (Paul Duvall) продемонстрирует, как инструмент с открытым исходным кодом для миграции баз данных LiquiBase помогает избавиться от неудобств при постоянном обмене между базами данных и приложениями.

Пол Дюваль, технический директор, Stelligent Incorporated

Paul DuvallПол Дюваль (Paul Duvall) является техническим директором компании Stelligent Incorporated – консалтинговой фирмы, которая помогает командам разработчиков оптимизировать гибкие методологии разработки программного обеспечения. Он также соавтор книги Continuous Integration: Improving Software Quality and Reducing Risk (Addison-Wesley, 2007 г.). Он принимал участие в создании книг UML 2 Toolkit (Wiley, 2003 г.) и No Fluff Just Stuff Anthology (Pragmatic Programmers, 2007 г.).



06.12.2010

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

  • ручное внесение изменений в БД;
  • разные версии БД у разных участников команды разработчиков;
  • непоследовательные подходы к внесению изменений (в базу данных или данные);
  • неэффективные механизмы ручного управления изменениями при переходах между версиями баз данных.

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

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

Об этом цикле статей

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

Рисунок 1. Ручное внесение изменений в таблицу базы данных
Рисунок 1. Ручное внесение изменений в таблицу базы данных

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

  • использование инструмента LiquiBase для миграции между различными версиями одной и той же базы данных;
  • автоматическое выполнение миграции базы данных;
  • способы последовательного внесения изменений в базе данных;
  • выполнение рефакторинга базы данных при помощи LiquiBase.

На рисунке 2 сервер постоянной интеграции и сборки (build/continuous Integration server) опрашивает на предмет изменений систему контроля версий (например, Subversion). Когда сервер обнаруживает изменение в репозитории, он запускает автоматический сценарий сборки, который использует LiquiBase для обновления базы данных

Рисунок 2. Автоматизация миграции базы данных
Рисунок 2. Автоматизация миграции базы данных

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

Что именно изменяется? DDL, DML, схемы, базы данных или данные

В этой статье термин изменения в базе данных используется для обозначения структурных изменений в базе данных с помощью DDL-сценариев (Data Definition Language - язык определения данных). (Некоторые поставщики баз данных называют DDL-сценарии схемами.) Под изменениями данных будут пониматься изменения, сделанные в базе данных при помощи DML-сценариев (Data Manipulation Language - язык манипулирования данными).

Управление изменениями в базе данных с помощью LiquiBase

Продукт LiquiBase, развиваемый с 2006 года, - это бесплатный инструмент с открытым исходным кодом, предназначенный для миграции с одной версии базы данных на другую (см. раздел Ресурсы). Кроме LiquiBase, имеются и другие утилиты с открытым исходным кодом, предназначенные для миграции баз данных, например, openDBcopy и dbdeploy. LiquiBase поддерживает 10 типов баз данных, включая DB2, Apache Derby, MySQL, PostgreSQL, Oracle, Microsoft® SQL Server, Sybase и HSQL.

Чтобы установить LiquiBase, необходимо загрузить заархивированный файл ядра LiquiBase, распаковать его и поместить файл liquibase-version.jar в общесистемный путь поиска программ (переменная PATH).

Чтобы начать работать с LiquiBase, нужно выполнить четыре шага:

  1. Создать файл с журналом изменений в базе данных (change log).
  2. Определить набор изменений (change set - XML-элемент) внутри этого файла.
  3. Применить набор изменений к базе данных через командную строку или сценарий сборки.
  4. Проверить изменения в базе данных.

Создание файла change log и XML-элемента change set

Первым шагом для работы с LiquiBase, как демонстрируется в листинге 1, является создание XML-файла, известного как журнал изменений в базе данных (database change log):

Листинг 1. Определение набора изменений в XML-файле LiquiBase
<?xml version="1.0" encoding="UTF-8"?>

<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog/1.7"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog/1.7
         http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-1.7.xsd">
  <changeSet id="2" author="paul">
    <createTable tableName="brewer">
      <column name="id" type="int">
        <constraints primaryKey="true" nullable="false"/>
      </column>
      <column name="name" type="varchar(255)">
        <constraints nullable="false"/>
      </column>
      <column name="active" type="boolean" defaultValue="1"/>
    </createTable>
  </changeSet>
</databaseChangeLog>

Немного об XML

Некоторые читатели знакомы с миром XML-сценариев, некоторые нет. Многие разработчики даже привыкли писать программы с использованием XML-сценариев (например, при помощи Apache Ant), но знание XML не является обязательным для администратора баз данных. Недавно я решил показать одному знакомому администратору базы данных некоторые из возможностей LiquiBase. Ему понравились многие из мощных возможностей этой утилиты для управления изменениями в базе данных, но он скептично отнесся к вопросу о том, смогут ли администраторы баз данных освоить XML-подобный язык. Я убедил его, что LiquiBase также поддерживает вызов произвольных SQL-сценариев при помощи тега sqlFile и поддерживает рефакторинг через тег sql.

Как можно видеть, log-файл database change содержит ссылку на XML-схему (файл dbchangelog-1.7.xsd включен в установочный пакет LiquiBase). В узле change log создается узел <changeSet>. Как показано в схеме LiquiBase, внутри <changeSet> в структурированном формате определяются изменения в базе данных.

Выполнение LiquiBase из командной строки

После определения блока change set можно запустить LiquiBase из командной строки способом, показанным в листинге 2:

Листинг 2. Запуск LiquiBase из командной строки
liquibase --driver=org.apache.derby.jdbc.EmbeddedDriver \
--classpath=derby.jar \
--changeLogFile=database.changelog.xml \
--url=jdbc:derby:brewery;create=true \ 
--username= --password= \
update

В этом примере при запуске LiquiBase ему передаются следующие параметры:

  • драйвер базы данных;
  • значение переменной classpath для определения местоположения JAR-файла драйвера базы данных;
  • название change log-файла, который был создан в листинге 1 - database.changelog.xml;
  • URL-адрес базы данных;
  • имя пользователя и пароль.

В заключение в листинге 2 вызывается команда update, которая указывает LiquiBase внести изменения в базу данных.

Запуск LiquiBase в ходе автоматизированной сборки

Вместо того чтобы вызывать LiquiBase из командной строки, можно сделать процесс внесения изменения в базу данных частью автоматизированного процесса сборки, вызывая для этого задачу Ant, предоставляемую LiquiBase. Листинг 3 содержит пример использования этой задачи Ant:

Листинг 3. Ant-сценарий для выполнения задачи Ant updateDatabase
<target name="update-database">
  <taskdef name="updateDatabase" classname="liquibase.ant.DatabaseUpdateTask" 
    classpathref="project.class.path" />
  <updateDatabase changeLogFile="database.changelog.xml"
    driver="org.apache.derby.jdbc.EmbeddedDriver"
    url="jdbc:derby:brewery"
    username=""
    password=""
    dropFirst="true"
    classpathref="project.class.path"/>
</target>

В листинге 3 создается элемент с названием update-database. В нем определяется Ant-задача с именем updateDatabase, относящаяся к LiquiBase. В нее передаются необходимые значения, включая changeLogFile (определяет файл с журналом изменений, описанный в листинге 1) и информацию для подключения к базе данных. В переменной classpath, задаваемой атрибутом classpathref, должен содержаться путь к файлу liquibase-version.jar.

До и после

Рисунок 3 показывает состояние базы данных до того, как в нее был внесен набор изменений из листинга 1:

Рисунок 3. Состояние базы данных до выполнения набора изменений LiquiBase
Рисунок 3. Состояние базы данных до выполнения набора изменений LiquiBase

Рисунок 4 показывает результаты выполнения набора изменений из элемента change set для базы данных из командной строки (как показано в листинге 2) или из Ant (как показано в листинге 3):

Рисунок 4. Изменения, внесенные в базу данных после выполнения набора изменений LiquiBase
Рисунок 4. Изменения, внесенные в базу данных после выполнения набора изменений LiquiBase

Ряд аспектов на рисунке 4 заслуживает отдельного рассмотрения. Кроме новых таблиц, которые были созданы на основе описания в XML-элементе change set (см. листинг 1), LiquiBase создал две специальные таблицы. Первая LiquiBase-специфичная таблица, называемая databasechangelog, хранит историю всех изменений, сделанных в базе данных - она позволяет отслеживать, кто внес изменения в базу данных и зачем. Вторая специфичная для LiquiBase таблица, databasechangelock, определяет пользователя, который заблокировал базу данных для внесения в нее изменений.

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


Интеграция изменений в БД

Автоматизируйте процесс администрирования баз данных

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

В течение последних лет команды разработчиков привносили в управление изменениями в базах данных принципы, подобные тем, которые используются при работе с исходным кодом. Поэтому вполне закономерно создание сценариев изменения для БД, загрузка этих сценариев в репозитории исходного кода и интеграция этих изменений в процесс постоянной сборки (Continuous-Integration process). В таблице 1 предоставлен обзор ключевых возможностей, которые следует использовать командам разработчиков при автоматизации процесса внесения изменений в БД:

Таблица 1. Подходы к интеграции баз данных
МетодикаОписание
Создание DDL- и DML-сценариевВсе сценарии изменения БД должны иметь возможность запуска из командной строки.
Использование системы контроля версий для управления изменениями в данныхДля управления изменениями в базе данных используется репозиторий системы контроля версий.
Локальная база данных - "песочница"Каждый разработчик вносит изменения в собственную локальную базу данных.
Автоматизированная интеграция в базу данныхПроцесс внесения изменений в базу данных стать частью процесса автоматической сборки.

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


Внесение изменений в уже существующую базу данных

Когда в приложение добавляются новые возможности, часто возникает необходимость вносить структурные изменения в базу данных или изменять ограничения таблиц. LiquiBase поддерживает более 30 команд для рефакторинга баз данных (см. раздел Ресурсы). Этот раздел затрагивает четыре из этих команд: добавление столбца, удаление столбца, создание таблицы и управление данными.

Добавление столбца

Иногда возникает ситуация, когда невозможно в самом начале проекта заранее предусмотреть и создать в таблицах все столбцы, которые понадобятся впоследствии. Также иногда пользователи могут потребовать новых возможностей - например, сбора большего количества данных, - что может потребовать добавления новых столбцов. В листинге 4 к таблице distributor в базе данных добавляются столбцы при помощи команды рефакторинга LiquiBase addColumn:

Листинг 4. Использование команды Add Column для рефакторинга базы данных через набор изменений LiquiBase
<changeSet id="4" author="joe">
  <addColumn tableName="distributor">
    <column name="phonenumber" type="varchar(255)"/>
  </addColumn> 
</changeSet>

Новый столбец phonenumber имеет тип данных varchar.

Удаление столбца

Теперь предположим, что через несколько версий было решено удалить столбец phonenumber, добавленный в листинге 4. Это легко сделать при помощи XML-команды dropColumn, как показано в листинге 5:

Листинг 5. Удаление столбца из базы данных
<dropColumn tableName="distributor" columnName="phonenumber"/>

Создание таблицы

Добавление новой таблицы к базе данных - еще одна задача, часто возникающая при рефакторинге базы данных. В листинге 6 создается новая таблица с именем distributor; при этом определяются столбцы, ограничения и значения по умолчанию для новой таблицы:

Листинг 6. Создание новой таблицы в LiquiBase
<changeSet id="3" author="betsey">
  <createTable tableName="distributor">
    <column name="id" type="int">
      <constraints primaryKey="true" nullable="false"/>
    </column>
    <column name="name" type="varchar(255)">
      <constraints nullable="false"/>
    </column>
    <column name="address" type="varchar(255)">
      <constraints nullable="true"/>
    </column>
    <column name="active" type="boolean" defaultValue="1"/>
  </createTable>
</changeSet>

В данном примере команда рефакторинга createTable является вложенным узлом XML-элемента changeSet (команда createTable также использовалась в примере из листинга 1).

Управление данными

После рефакторинга структуры БД (например, с помощью команд Add Column и Create Table) часто бывает нужно вставить данные в измененные таблицы. Более того, может потребоваться изменение уже существующих данных в таблицах преобразования и других типах таблиц. В листинге 7 приведен пример того, как вставить данные через XML-элемент changeSet LiquiBase:

Листинг 7. Вставка данных через XML-элемент changeSet LiquiBase
<changeSet id="3" author="betsey">
  <code type="section" width="100%">
  <insert tableName="distributor">
    <column name="id" valueNumeric="3"/>
    <column name="name" value="Manassas Beer Company"/>
  </insert>
  <insert tableName="distributor">
    <column name="id" valueNumeric="4"/>
    <column name="name" value="Harrisonburg Beer Distributors"/>
  </insert>
</changeSet>

Возможно, у вас уже есть готовые SQL-сценарии для управления данными, или возможности LiquiBase XML кажутся несколько ограниченными. Кроме того, SQL-сценарии иногда удобнее для внесения массовых изменений в БД. LiquiBase может работать с SQL-файлами. В листинге 8 показан фрагмент кода, в котором в XML-элементе changeSet вызывается файл insert-distributor-data.sql, который вставляет данные в таблицу distributor:

Листинг 8. Запуск произвольного SQL-файла из XML-элемента changeSet LiquiBase
<changeSet id="6" author="joe">
  <sqlFile path="insert-distributor-data.sql"/>
</changeSet>

LiquiBase поддерживает многие другие команды рефакторинга базы данных, включая добавление таблицы преобразования и слияние столбцов. Они определяются так же, как показано в листингах с 4 по 8-й.


Постоянная синхронизация данных

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

  • показать, как использовать LiquiBase для создания сценариев миграции баз данных и как сделать эти изменения частью автоматизированного процесса сборки;
  • описать принципы и практические подходы к интеграции баз данных, обеспечивающие согласованность процесса;
  • показать, как использовать команды рефакторинга типа addColumn и createTable для изменения структуры таблиц и обновления данных средствами LiquiBase

Таблица 2 подытоживает некоторые возможностей, предоставляемых LiquiBase:

Таблица 2. Сводная информация по возможностям LiquiBase
ВозможностьОписание
Поддержка различных баз данныхПоддержка DB2, Apache Derby, MySQL, PostgreSQL, Oracle, Microsoft SQL Server, Sybase, HSQL и других производителей.
Просмотр истории изменений, сделанных в БДИспользуя таблицу databasechangelog,можно просмотреть изменения, внесенные в базу данных.
Создание журналов различия баз данныхУзнать об изменениях, которые были внесены в БД, минуя наборы изменений LiquiBase.
Возможность выполнения произвольных SQL-сценариевИспользование LiquiBase для вызова написанных ранее SQL-сценариев.
Утилиты для отката внесенных измененийПоддержка возможности отката любых внесенных в БД изменений.

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

Ресурсы

Научиться

  • Automation for the people: Hands-free database migration: оригинал статьи (EN).
  • LiquiBase: ресурсы по LiquiBase на Интернет-сайте проекта, включая полный список команд рефакторинга, которые поддерживает LiquiBase.(EN)
  • Incremental Migration: (EN) (Мартин Фаулер, martinfowler.com, июль 2008 г.): в статье утверждается, что поскольку миграция данных является сложным процессом, ее следует выполнять чаще.
  • Refactoring Databases: Evolutionary Database Design: (Скотт Эмблер и Прамод Садаладж, Addison-Wesley Professional, 2006 г.): книга о том, как развивать и управлять схемами базы данных параллельно с управлением исходным кодом.(EN)
  • Continuous Integration: Improving Software Quality and Reducing Risk (Поль Дюваль, Стив Матиас и Эндрю Гловер, Addison-Wesley Signature Series, 2007 г.): примеры в главе 5, "Continuous Database Integration", ("Постоянная интеграция базы данных") демонстрируют, как встроить интеграцию базы данных в автоматизированный процесс сборки.(EN)
  • Recipes for Continuous Database Integration: Evolutionary Database Development: (Прамод Садаладж, Addison-Wesley Professional, 2007 г.): книга о том, как реализовать процесс постоянной интеграции для базы данных.(EN)
  • Evolutionary Database Design (EN) (Фаулер и Садаладж, martinfowler.com, 2003 г.): статья о постоянной интеграции и автоматизированном процессе рефакторинга при разработке баз данных.(EN)
  • Database Integration in your Build scripts (EN) (Поль Дюваль, testearly.com, июль 2006 г.): статья о применении DDL- и DML-сценариев в рамках автоматизированного процесса сборки.
  • developerWorks на Твиттер.(EN)
  • Конференции, выставки, Web-трансляции и другие события по всему миру, которые могут заинтересовать разработчиков проектов с открытым кодом, использующих продукты IBM.(EN)
  • Информация и презентации о технологиях IBM с открытым кодом и бесплатных продуктах в разделе developerWorks On demand demos.(EN)
  • Safarit technology bookstore: Интернет-магазин технической литературы.(EN)

Получить продукты и технологии

  • LiquiBase: загрузите LiquiBase и автоматизируйте процесс миграции баз данных.(EN)
  • Ant: загрузите Ant и обеспечьте предсказуемость и повторяемость процесса сборки ПО.(EN)
  • Загрузите ознакомительные версии продуктов IBM и получите доступ к инструментам для разработки и отладки приложений, а также ПО связующего уровня DB2®, Lotus®, Rational®, Tivoli® и WebSphere®.(EN)
  • Усовершенствуйте свой проект с открытым исходным кодом с помощью ознакомительных версий ПО от IBM, которые можно скачать с сайта или заказать на DVD.(EN)

Обсудить

  • " Форум, посвященный улучшению качества программного кода: постоянный участник сообщества developerWorks Эндрю Гловер (Andrew Glover), консультант, фокусирующийся на вопросах качества программного кода, ведет дискуссии на это модерируемом форуме. (EN)
  • Площадка по ускоренной разработке: постоянный участник сообщества developerWorks Эндрю Гловер (Andrew Glover) ведет свой портал, посвященный всем вопросам, связанным с тестированием, непрерывной интеграцией, оценкой и рефакторингом программного кода. (EN)

Комментарии

developerWorks: Войти

Обязательные поля отмечены звездочкой (*).


Нужен IBM ID?
Забыли Ваш IBM ID?


Забыли Ваш пароль?
Изменить пароль

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


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

Вся введенная информация защищена.

Выберите имя, которое будет отображаться на экране



При первом входе в developerWorks для Вас будет создан профиль и Вам нужно будет выбрать Отображаемое имя. Оно будет выводиться рядом с контентом, опубликованным Вами в developerWorks.

Отображаемое имя должно иметь длину от 3 символов до 31 символа. Ваше Имя в системе должно быть уникальным. В качестве имени по соображениям приватности нельзя использовать контактный e-mail.

Обязательные поля отмечены звездочкой (*).

(Отображаемое имя должно иметь длину от 3 символов до 31 символа.)

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


Вся введенная информация защищена.


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=40
Zone=Технология Java, Open source
ArticleID=594382
ArticleTitle=Автоматизация для программистов: Автоматизированная миграция баз данных
publish-date=12062010