← Назад к вопросам

В чем разница между Flyway и Liquibase?

2.3 Middle🔥 121 комментариев
#Базы данных и SQL

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

# Разница между Flyway и Liquibase

Краткое сравнение

КритерийFlywayLiquibase
ЯзыкSQL (native)XML, YAML, JSON, SQL
ВерсионированиеПростое (V1, V2, V3)Более гибкое (changeset'ы)
ОткатТолько undo scriptsВстроенный откат
СложностьПростая, понятнаяБолее мощная, сложнее
РазработчикAxel FontaineLiquibase Inc.
CommunityАктивноеОчень активное
EnterpriseБесплатенЕсть платная версия

Определение

Flyway

Flyway — простой инструмент версионирования БД на native SQL. Использует файлы с именами вроде V1__Initial_schema.sql, V2__Add_users_table.sql.

Философия: "Keep it simple" — просто SQL файлы, простой контроль.

Liquibase

Liquibase — мощный инструмент миграций БД с поддержкой multiple форматов (XML, YAML, SQL). Использует концепцию changesets с возможностью отката и условного выполнения.

Философия: "Database agnostic" — одна миграция работает на PostgreSQL, MySQL, Oracle и т.д.

Структура файлов

Flyway

Проста и понятна:

src/main/resources/db/migration/
├── V1__Initial_schema.sql
├── V2__Add_users_table.sql
├── V3__Add_email_column.sql
└── V4__Create_indexes.sql

Внутри файла — pure SQL:

-- V1__Initial_schema.sql
CREATE TABLE users (
    id SERIAL PRIMARY KEY,
    name VARCHAR(255) NOT NULL,
    email VARCHAR(255) UNIQUE
);

CREATE TABLE orders (
    id SERIAL PRIMARY KEY,
    user_id INT REFERENCES users(id),
    amount DECIMAL(10, 2)
);

Liquibase

Могу использовать разные форматы. XML пример:

<!-- db/changelog/db.changelog-master.xml -->
<databaseChangeLog
    xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog
    http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.0.xsd">

    <changeSet id="1" author="john">
        <createTable tableName="users">
            <column name="id" type="INT" autoIncrement="true">
                <constraints primaryKey="true"/>
            </column>
            <column name="name" type="VARCHAR(255)">
                <constraints nullable="false"/>
            </column>
            <column name="email" type="VARCHAR(255)">
                <constraints unique="true"/>
            </column>
        </createTable>
    </changeSet>

    <changeSet id="2" author="john">
        <createTable tableName="orders">
            <column name="id" type="INT" autoIncrement="true">
                <constraints primaryKey="true"/>
            </column>
            <column name="user_id" type="INT">
                <constraints foreignKeyName="fk_user" references="users(id)"/>
            </column>
            <column name="amount" type="DECIMAL(10,2)"/>
        </createTable>
    </changeSet>
</databaseChangeLog>

YAML пример (более читаемо):

# db/changelog/db.changelog-master.yaml
databaseChangeLog:
  - changeSet:
      id: 1
      author: john
      changes:
        - createTable:
            tableName: users
            columns:
              - column:
                  name: id
                  type: INT
                  autoIncrement: true
                  constraints:
                    primaryKey: true
              - column:
                  name: name
                  type: VARCHAR(255)
                  constraints:
                    nullable: false
              - column:
                  name: email
                  type: VARCHAR(255)
                  constraints:
                    unique: true

  - changeSet:
      id: 2
      author: john
      changes:
        - createTable:
            tableName: orders
            columns:
              - column:
                  name: id
                  type: INT
                  autoIncrement: true
                  constraints:
                    primaryKey: true
              - column:
                  name: user_id
                  type: INT
                  constraints:
                    foreignKeyName: fk_user
                    references: users(id)
              - column:
                  name: amount
                  type: DECIMAL(10,2)

Практические примеры

Flyway в Spring Boot

# application.yml
spring:
  flyway:
    baseline-on-migrate: true  # Инициализировать baseline на пустой БД
    baseline-version: 0
    out-of-order: false        # Не позволять out-of-order миграции
locations:
  - classpath:db/migration
// pom.xml
<dependency>
    <groupId>org.flywaydb</groupId>
    <artifactId>flyway-core</artifactId>
    <version>9.16.3</version>
</dependency>

При запуске приложения Flyway автоматически:

  1. Сканирует /db/migration
  2. Находит новые V* файлы
  3. Запускает их по порядку
  4. Записывает информацию в flyway_schema_history таблицу

Liquibase в Spring Boot

# application.yml
spring:
  liquibase:
    change-log: classpath:db/changelog/db.changelog-master.yaml
    enabled: true
// pom.xml
<dependency>
    <groupId>org.liquibase</groupId>
    <artifactId>liquibase-core</artifactId>
    <version>4.20.0</version>
</dependency>

Откаты и отмены

Flyway (Undo скрипты)

Для отката нужны отдельные файлы:

src/main/resources/db/migration/
├── V1__Initial_schema.sql
├── U1__Initial_schema.sql      ← Undo скрипт!
├── V2__Add_users_table.sql
└── U2__Add_users_table.sql     ← Undo скрипт!
-- U2__Add_users_table.sql (Откат для V2)
DROP TABLE IF EXISTS orders;

Откат командой:

flyway undo

Liquibase (Встроенный откат)

Oткат встроен в changeset'ы:

<changeSet id="2" author="john">
    <createTable tableName="orders">
        <!-- ... -->
    </createTable>
    
    <!-- Liquibase может автоматически сгенерировать undo -->
    <rollback>
        <dropTable tableName="orders"/>
    </rollback>
</changeSet>

Откат командой:

liquibase rollback-count --count=1

Условные миграции

Flyway (Сложнее)

Фlyway не имеет встроенной поддержки условных миграций. Нужен workaround:

-- V3__Add_feature_X.sql
-- Не могу проверить in SQL, нужно делать на уровне приложения
ALTER TABLE users ADD COLUMN feature_flag BOOLEAN DEFAULT false;

Liquibase (Встроенная поддержка)

можно использовать preconditions:

<changeSet id="3" author="john">
    <preConditions onFail="MARK_RAN">
        <!-- Проверяй, есть ли эта таблица -->
        <not>
            <tableExists tableName="audit_log"/>
        </not>
    </preConditions>
    
    <createTable tableName="audit_log">
        <column name="id" type="INT" autoIncrement="true">
            <constraints primaryKey="true"/>
        </column>
    </createTable>
</changeSet>

Поддержка разных БД

Flyway

Делает большую часть работы, но иногда нужны specific файлы:

src/main/resources/db/migration/
├── V1__Init.sql              ← Universal
├── V2__Index_postgres.sql    ← Только для PostgreSQL
└── V2__Index_mysql.sql       ← Только для MySQL

Средезва:

flyway.sql-migration-suffixes=.sql
flyway.clean-disabled=false

Liquibase

Лучше поддерживает DB-specific синтаксис:

<changeSet id="4" author="john" dbms="postgresql">
    <sql>
        CREATE INDEX idx_user_email ON users(email);
    </sql>
</changeSet>

<changeSet id="5" author="john" dbms="mysql">
    <sql>
        CREATE INDEX idx_user_email ON users(email(50));
    </sql>
</changeSet>

Когда использовать что

Используй Flyway, если:

✅ Проект простой ✅ Разработчики знают SQL хорошо ✅ Не нужны сложные условные миграции ✅ Хочешь простоту и скорость ✅ Вся БД одного типа (все PostgreSQL)

// Пример: Стартап, простая БД
@SpringBootApplication
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
        // Flyway стартует автоматически
    }
}

Используй Liquibase, если:

✅ Проект большой и сложный ✅ Нужны условные миграции ✅ Мультибаза (PostgreSQL в dev, Oracle в prod) ✅ Нужна история с автоматическим откатом ✅ Команда многоуровневая

// Пример: Enterprise приложение
@SpringBootApplication
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
        // Liquibase с preconditions и rollback'ами
    }
}

В проекте PrepBro

По конфигу видно, что используется Goose (не Flyway и не Liquibase), но если выбирать:

  • Для стартапа/MVP: Flyway (простая, быстрая)
  • Для масштабирования: Liquibase (гибкая, условная логика)

Итоговый ответ

Flyway:

  • Простая и понятная
  • Использует native SQL
  • Нет встроенного отката (нужны undo скрипты)
  • Лучше для простых проектов

Liquibase:

  • Более мощная и гибкая
  • Поддерживает XML, YAML, JSON
  • Встроенный откат и условные миграции
  • Лучше для больших проектов и сложных сценариев

Выбор зависит от сложности проекта и требований к миграциям.

В чем разница между Flyway и Liquibase? | PrepBro