Flyway – простая миграция базы данных.

Введение 🔍

Flyway icon

Проблематика

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

  1. ⚠️ Риск ошибок
    • Каждое новое изменение схемы базы данных несет в себе потенциальные риски, которые могут привести к сбоям в работе приложения или нарушению целостности данных.
  2. 🔄 Сложность синхронизации изменений
    • В современных проектах используются несколько сред разработки (test, development, production). Синхронизация всех изменений между этими средами — довольно трудоемкий процесс. Автоматизация этого процесса не только снижает трудозатраты, но также исключает вероятность человеческих ошибок.
  3. ⚔️ Параллельная разработка
    • Использование Flyway позволяет удобно разрешать конфликты связанные с параллельной разработкой, автоматически выявляя проблемы с версионностью и последовательностью миграций.
  4. Трудоемкость ручного управления
    • Эволюция базы данных может достигать такого уровня, что ручная поддержка становится сверх задачей. Особенно это проявляется при использовании технологий непрерывной интеграции и доставки (CI/CD), где без автоматизации разработчик вынужден самостоятельно поддерживать консистентность базы данных при каждом развертывании и тестировании системы.

Решение: Flyway

Что такое Flyway? – Flyway призван автоматизировать процесс миграций. Миграция — это процесс изменения структуры базы данных (эволюции), который описывается с помощью специального файла миграции. Эти файлы формируют историю изменений, благодаря которой возможна автоматическая установка обновлений во всех средах, обеспечивая согласованность и актуальность базы данных.

Как работает Flyway:

  • 🔍 Поиск истории изменений – Прежде всего Flyway попытается найти таблицу “flyway_schema_history”, которая содержит метаданные миграций.
  • 📊 Отслеживание версий схемы БД – Когда схема изменений будет найдена, он начнет сканировать classpath приложения на наличие файлов миграции. Это могут быть .sql или .java файлы. Эти файлы сортируются на основании ихней версии, которая должна быть указана в имени следуя шаблону “V1__name.sql”.
  • 🔄 Согласованность сред – Анализируя различия между текущим состоянием (flyway_schema_history) и найденными файлами миграции, flyway производит обновления основываясь на старшинстве версий. Все среды используют одну и ту же схему базы данных, что позволяет гарантировать их согласованность.

Миграции 📜

Это основной механизм Flyway, позволяющий накатывать sql-скрипт на базу данных, в котором, последовательно сописаны требующиеся операции. Каждое изменение с помощью скрипта, будет зафиксировано в “flyway_schema_history”.

Каждая миграция имеет уникальный идентификатор (обычно номер версии) и может включать в себя следующие действия:

  • создание, изменение или удаление таблиц, индексов, триггеров и других объектов базы данных;
  • внесение изменений в существующие данные;
  • выполнение сложных процедур или скриптов.

Версионные и повторяющиеся миграции

Flyway поддерживает два основных типа миграций.

Версионные миграции (Versioned Migrations) представляют собой набор изменений, которые пронумерованы в соответствии с их порядком применения. Эти миграции нумеруются с использованием схемы V<номер версии>__<описание>.sql (например, V1__Create_users_table.sql). Flyway применяет такие миграции строго по порядку номеров версий, начиная с самой ранней.

Основные особенности версионных миграций:

  • Нумерация позволяет точно определять последовательность изменений.
  • После применения миграция считается завершенной и повторно не выполняется.
  • Использование версионных миграций исключает возможность пропуска или случайного повторного применения изменений.

Повторяющиеся миграции

Повторяющиеся миграции (Repeatable Migrations) — это миграции, которые могут применяться повторно каждый раз, когда изменяется их содержание. Повторяющиеся миграции не имеют версии, а именуются по схеме R__<описание>.sql (например, R__Recalculate_user_statistics.sql).

Особенности повторяющихся миграций:

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

Валидация и исправление миграций

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

Основные этапы валидации миграций
  1. 🔍 Сравнение списка миграций: Flyway сравнивает список версионных и повторяющихся миграций, которые записаны в таблице истории миграций (flyway_schema_history), с теми, которые находятся в проекте (в файловой системе или другом источнике миграций).
  2. 🔑 Сравнение хеша: Для каждой версионной миграции Flyway сохраняет хеш-код содержимого миграционного файла. Этот хеш используется для проверки того, что содержимое миграций не изменилось с момента их первоначального применения.
  3. 🔢 Проверка последовательности версий: Flyway проверяет, что миграции были применены в правильном порядке, согласно их номерам версий.
  4. Согласованность версионных и повторяющихся миграций:
    • 🔍 Версионная миграция (V1__Create_users_table.sql): Если вы измените эту миграцию после того, как она была применена, Flyway выбросит ошибку валидации при следующем запуске, так как хеш миграции изменится.
    • 🔁 Повторяющаяся миграция (R__Recalculate_user_statistics.sql): Если вы измените этот файл, Flyway при следующем запуске снова выполнит эту миграцию, чтобы обновить данные согласно новым инструкциям.

Интеграция Flyway в проект 🚀

Интеграция Flyway в Java-проект достаточно проста и требует выполнения нескольких шагов.

📦 Добавление зависимостей: чтобы интегрировать Flyway в проект начнем с добавления заисимостей в “pom.xml”. Помимо flyway-core будут также нужны базовые драйвера для СУБД. Пример с PostgreSQL:

         <dependency>
            <groupId>org.flywaydb</groupId>
            <artifactId>flyway-core</artifactId>
            <version>10.11.0</version>
        </dependency>

        <dependency>
            <groupId>org.flywaydb</groupId>
            <artifactId>flyway-database-postgresql</artifactId>
            <version>10.11.0</version>
        </dependency>

⚙️ Настройка и запуск миграций
После добавления зависимостей настройте и запустите соответствующую команду.

 Flyway flyway = 
            Flyway.configure().dataSource(url, user, password).load();
 flyway. migrate();

🔄 Автоматический запуск в Spring Framework
В случае использования Spring Framework, вы можете автоматизировать процесс миграции, создав Spring Bean и попросить его вызвать метод migrate() после инициализации.

    @Bean(initMethod = "migrate")
    public Flyway flywayMigration(DataSource dataSource) {

        return Flyway.configure()
                .dataSource(dataSource)
                .load();
    }

Этот метод требует внедрения кода в логику инициализации приложения, что может быть не всегда удобно. Также следует обратить внимание на то, что EntityManager может зависеть от корректно выполненых миграций, поэтому стоит добавить зависимость для EM Bean:
< @DependsOn(“flywayMigration”) >

🔧 Использование Maven плагина
Для упрощения процесса настройки и выполнения миграций, у Flyway есть возможность использовать специальный Maven плагин:

 <build>
        <plugins>
            <plugin>
                <groupId>org.flywaydb</groupId>
                <artifactId>flyway-maven-plugin</artifactId>
                <version>10.11.0</version>
                <executions>
                    <execution>
                        <phase>pre-integration-test</phase>
                        <goals>
                            <goal>info</goal>
                            <goal>migrate</goal>
                        </goals>
                    </execution>
                </executions>
                <configuration>
                    <url>jdbc:postgresql://localhost:5432/bookmanager</url>
                    <user>aleos</user>
                    <password>root</password>
                </configuration>
                <dependencies>
                    <dependency>
                        <groupId>org.flywaydb</groupId>
                        <artifactId>flyway-database-postgresql</artifactId>
                        <version>10.11.0</version>
                    </dependency>
                </dependencies>
            </plugin>
        </plugins>
    </build>

Этот плагин позволяет выполнять миграции автоматически во время сборки проекта, задавая явно фазы и цели выполнения
Примечание: Нужно убедиться, что при сборке используется Maven, так как некоторые IDE, например IntelliJ IDEA, могут использовать свой внутренний компилятор, что приведет к пропуску задач Flyway.
Заметка: Значения конфигурации могут быть также переданы через переменные окружения или системные свойства для повышения безопасности и гибкости конфигурации.

Flyway по умолчанию ищет файлы миграции в директории src/main/resources/db/migration, и имя каждого файла должно следовать шаблону V1__description.sql. Версии могут быть как линейными (V1, V2), так и версионными с использованием десятичных чисел (V1.1, V1.2) для более гибкого управления миграциями.

Базовые команды

  • Migrate – Команда migrate обновляет схему базы данных до последней версии, доступной среди файлов миграции. Если таблица истории миграций отсутствует, она будет создана. Рекомендуется применять во время запуска приложения, чтобы гарантировать актуальность и консистентность базы данных. Метод является идемпотентным.
  • Baseline – Операция базирования используется для установления начальной точки управления миграциями в “чистой” базе данных, которая ранее не была под контролем Flyway. Это особенно полезно для существующих баз данных, где уже присутствуют некоторые схемы, но не ведется история миграций. Установка базовой линии позволяет Flyway начать управление миграциями, начиная с определенной версии, исключая предыдущие изменения.
// default base version 1
flyway baseline

flyway baseline -baselineVersion=1.5
Здесь была удалена flyway_schema_history и выполнена команда: flyway baseline.
Теперь Initial schema игнорируется и flyway не несет ответственности за состоянии базы данных до базовой линии.
  • Info – Выводит историю миграций в консоль, включая как уже примененные, так и ожидающие выполнения. Это полезно для мониторинга и отладки процессов миграции.
  • Clean – удаляет все объекты в присутствующих схемах. Удобно в процессах разработки и тестирования. Существует предохранитель в виде параметра “cleanDisabled”, по умолчания установлен в “true”, для предотвращения случайного удаления данных.
  • Repair – Если вы сделали изменения в существующих миграциях, которые уже были применены (это вызовет проблемы с checksum), repair поможет скорректировать таблицу истории миграций и обновит контрольные суммы (“checksum”). Но будьте внимательны – это может создать разницу между существующими и будущими схемами.
  • Validate – помогает убедится, что все миграции примененные к схеме БД совпадают с миграциями в наличии.
  • Undo – отменяет последняя примененную миграцию. Не доступно в открытой версии.

Внешние инструменты и Flyway 🌐

Spring или другие фреймворки: Автоматически подставляют нужные параметры конфигурации для различных окружений и могут управлять жизненным циклом миграций (например, выполняя миграции при старте приложения).

Maven/Gradle: Обеспечивают выполнение миграций в процессе сборки, предоставляют плагины для автоматизации задач.

CI/CD системы: Автоматизируют процессы развертывания, включая выполнение миграций, используя команды Flyway (flyway:migrate) в рамках общего пайплайна.

Таким образом, поддержка миграций на разных окружениях и интеграция с CI/CD процессами действительно зависят от правильной настройки окружения и инструментов, а не от самого Flyway. Flyway выполняет свою задачу по управлению миграциями, в то время как другие инструменты создают условия для его эффективного использования в различных контекстах.

Пример создания миграции ✏️

-- V1__Create_employees_table.sql

-- Создание таблицы employees
CREATE TABLE employees (
    id SERIAL PRIMARY KEY,
    first_name VARCHAR(100) NOT NULL,
    last_name VARCHAR(100) NOT NULL,
    email VARCHAR(255) NOT NULL UNIQUE,
    hire_date DATE NOT NULL,
    department VARCHAR(100)
);

-- Добавление индекса на поле email
CREATE INDEX idx_email ON employees(email);

-- Вставка начальных данных
INSERT INTO employees (first_name, last_name, email, hire_date, department) VALUES 
('John', 'Doe', 'john.doe@example.com', '2023-01-15', 'Engineering'),
('Jane', 'Smith', 'jane.smith@example.com', '2022-10-01', 'Marketing'),
('Robert', 'Johnson', 'robert.johnson@example.com', '2024-03-21', 'Sales');

Этот скрипт можно поместить в файл с именем, соответствующим соглашению о версиях миграций Flyway, например V1__Create_employees_table.sql, и добавить его в директорию миграций вашего проекта (обычно src/main/resources/db/migration). Flyway автоматически применит этот скрипт при выполнении миграций.

Заключение 🎯

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


Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top