Введение в Flyway: что это и зачем нужно
Flyway — это библиотека для управления версиями и миграциями баз данных (Database Migration Tool). В современной разработке программного обеспечения, особенно в командной работе и при использовании методологий CI/CD, возникает критическая необходимость синхронизировать структуру базы данных между разработчиками, тестовыми и продуктивными средами. Flyway решает эту задачу, позволяя описывать изменения схемы БД (создание таблиц, добавление колонок, индексов, триггеров и т.д.) в виде последовательных, версионированных SQL-скриптов или Java-классов.
Основная концепция Flyway проста: каждая миграция имеет уникальный номер версии (например, V1, V2, V3) и выполняется ровно один раз. Библиотека отслеживает, какие миграции уже были применены к конкретной базе данных, используя специальную таблицу (по умолчанию flyway_schema_history). Это гарантирует идемпотентность и воспроизводимость состояния базы данных.
Зачем использовать Flyway?
- Версионирование схемы: Каждое изменение базы данных — это отдельная версия, которую можно откатить или применить.
- Автоматизация: Интеграция с Maven, Gradle, Spring Boot и CI/CD пайплайнами.
- Контроль целостности: Flyway проверяет контрольные суммы миграций, предотвращая случайные изменения уже выполненных скриптов.
- Простота: Для большинства задач достаточно написать обычный SQL-скрипт.
Установка Flyway для Java
Flyway не устанавливается через pip или npm, так как это Java-библиотека. Существует несколько способов добавить её в проект:
1. Maven (pom.xml)
<dependency>
<groupId>org.flywaydb</groupId>
<artifactId>flyway-core</artifactId>
<version>9.22.3</version> <!-- Актуальная версия на момент написания -->
</dependency>
<!-- Драйвер для вашей БД, например PostgreSQL -->
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>42.7.1</version>
</dependency>
2. Gradle (build.gradle)
implementation 'org.flywaydb:flyway-core:9.22.3'
implementation 'org.postgresql:postgresql:42.7.1'
3. Плагин Maven (для запуска из командной строки)
<plugin>
<groupId>org.flywaydb</groupId>
<artifactId>flyway-maven-plugin</artifactId>
<version>9.22.3</version>
<configuration>
<url>jdbc:postgresql://localhost:5432/mydb</url>
<user>myuser</user>
<password>mypassword</password>
</configuration>
</plugin>
4. Spring Boot (автоматическая конфигурация)
Если вы используете Spring Boot, достаточно добавить зависимость и настроить параметры в application.properties:
spring.flyway.enabled=true
spring.flyway.locations=classpath:db/migration
spring.datasource.url=jdbc:postgresql://localhost:5432/mydb
spring.datasource.username=myuser
spring.datasource.password=mypassword
Быстрый старт с примером кода
Рассмотрим минимальный пример использования Flyway в Java-приложении для создания таблицы users.
Шаг 1: Создайте структуру директорий для миграций
По умолчанию Flyway ищет SQL-скрипты в папке db/migration в classpath (например, src/main/resources/db/migration).
Шаг 2: Создайте файл миграции
Создайте файл V1__Create_users_table.sql в этой папке:
CREATE TABLE users (
id SERIAL PRIMARY KEY,
username VARCHAR(50) NOT NULL UNIQUE,
email VARCHAR(100) NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
Шаг 3: Напишите Java-код для запуска миграции
import org.flywaydb.core.Flyway;
public class FlywayExample {
public static void main(String[] args) {
// Создаем объект Flyway и настраиваем подключение к БД
Flyway flyway = Flyway.configure()
.dataSource("jdbc:postgresql://localhost:5432/mydb", "myuser", "mypassword")
.load();
// Запускаем миграцию
flyway.migrate();
System.out.println("Миграция успешно выполнена!");
}
}
Результат: После запуска этого кода в базе данных появится таблица users и служебная таблица flyway_schema_history, в которой будет запись о выполненной миграции V1.
Основные методы/функции Flyway (Java API)
Flyway предоставляет богатый API для управления миграциями. Рассмотрим 10 ключевых методов.
1. configure()
Что делает: Создает конфигуратор FluentConfiguration для настройки Flyway перед загрузкой. Это отправная точка для всех настроек.
Параметры: Не принимает параметров. Возвращает FluentConfiguration.
Пример:
Flyway flyway = Flyway.configure()
.dataSource(url, user, password)
.locations("classpath:db/migration")
.load();
2. dataSource(String url, String user, String password)
Что делает: Устанавливает подключение к базе данных. Можно передать как строки, так и готовый javax.sql.DataSource.
Параметры:
url— JDBC URL базы данных (например,jdbc:postgresql://localhost:5432/mydb).user— имя пользователя.password— пароль.
Пример:
Flyway flyway = Flyway.configure()
.dataSource("jdbc:mysql://localhost:3306/mydb", "root", "secret")
.load();
3. locations(String... locations)
Что делает: Указывает пути, где Flyway будет искать файлы миграций. По умолчанию — classpath:db/migration.
Параметры: Один или несколько строковых путей. Можно использовать префиксы classpath: и filesystem:.
Пример:
Flyway flyway = Flyway.configure()
.locations("classpath:db/migration", "filesystem:/opt/migrations")
.load();
4. migrate()
Что делает: Основной метод. Применяет все ожидающие миграции к базе данных. Возвращает объект MigrateResult, содержащий информацию о количестве выполненных миграций и времени выполнения.
Параметры: Нет.
Пример:
MigrateResult result = flyway.migrate();
System.out.println("Выполнено миграций: " + result.migrationsExecuted);
5. validate()
Что делает: Проверяет, что все примененные миграции соответствуют их текущим файлам (по контрольной сумме). Если какая-то миграция была изменена после выполнения, метод выбросит исключение FlywayException.
Параметры: Нет.
Пример:
try {
flyway.validate();
System.out.println("Валидация пройдена успешно.");
} catch (FlywayException e) {
System.err.println("Ошибка валидации: " + e.getMessage());
}
6. info()
Что делает: Возвращает информацию о состоянии миграций: какие применены, какие ожидают выполнения, их версии и описания. Возвращает объект MigrationInfoService.
Параметры: Нет.
Пример:
MigrationInfoService info = flyway.info();
for (MigrationInfo migrationInfo : info.all()) {
System.out.println("Версия: " + migrationInfo.getVersion() +
", Описание: " + migrationInfo.getDescription() +
", Статус: " + migrationInfo.getState());
}
7. clean()
Что делает: Полностью очищает базу данных: удаляет все объекты (таблицы, представления, процедуры) и сбрасывает таблицу истории миграций. Осторожно! Этот метод необратимо уничтожает данные.
Параметры: Нет.
Пример:
// Используется обычно в тестовых средах
flyway.clean();
System.out.println("База данных очищена.");
8. baseline()
Что делает: Создает базовую линию (baseline) для существующей базы данных. Это полезно, когда вы начинаете использовать Flyway на уже существующем проекте с живой базой данных. Метод помечает текущее состояние БД как версию 1 (или указанную вами), не применяя никаких миграций.
Параметры:
baselineVersion(опционально) — версия, с которой начинается отсчет.baselineDescription(опционально) — описание базовой линии.
Пример:
Flyway flyway = Flyway.configure()
.dataSource(url, user, password)
.baselineVersion("1")
.baselineDescription("Initial state of production DB")
.load();
flyway.baseline();
9. repair()
Что делает: Исправляет проблемы в таблице истории миграций. Например, удаляет записи о неудачных миграциях или исправляет контрольные суммы, если вы намеренно изменили уже выполненный скрипт (не рекомендуется, но бывает нужно).
Параметры: Нет.
Пример:
try {
flyway.repair();
System.out.println("Таблица истории восстановлена.");
} catch (FlywayException e) {
System.err.println("Ошибка восстановления: " + e.getMessage());
}
10. undo() (доступно в Flyway Teams/Enterprise)
Что делает: Откатывает последнюю примененную миграцию. Для этого необходимо создать специальный файл отката (например, U1__Create_users_table.sql). Важно: Этот метод недоступен в бесплатной версии Flyway Community Edition.
Параметры: Нет.
Пример:
// Требует файл U1__Create_users_table.sql с DROP TABLE users;
flyway.undo();
System.out.println("Последняя миграция откачена.");
Реальный практический пример использования
Рассмотрим сценарий разработки веб-приложения для интернет-магазина. Нам нужно управлять эволюцией схемы базы данных.
Задача: Добавить таблицу products, затем изменить её, добавив колонку price, и наконец создать индекс.
Структура миграций: