Pular para o conteúdo principal

Capítulo 3: Migração de Esquema com Flyway

Introdução​

Você já passou por essa situação?

"Espera, qual script SQL você executou em produção?"
"Aquele com as novas colunas... eu acho?"
"Mas tinham 3 versões! V1, V2 ou V2_final_final?"
💀

Flyway resolve esse problema ao versionar o seu esquema de banco de dados assim como você versiona seu código.


🎯 Objetivos do Capítulo​

Ao final deste capítulo, você saberá:

  1. ✅ Por que Flyway é essencial para produção
  2. ✅ Instalar e configurar Flyway com Spring Boot
  3. ✅ Criar scripts de migração
  4. ✅ Entender a convenção de nomenclatura
  5. ✅ Gerenciar migrações repetíveis
  6. ✅ Resolver problemas comuns

1. Por que Versionar o Esquema?​

O Problema​

Problemas:

  • Não se sabe qual script foi executado
  • Sem rastreio do histórico
  • Risco de esquecer uma migração
  • Impossível reproduzir o ambiente

A Solução: Flyway​

Vantagens:

  • ✅ Histórico completo das migrações
  • ✅ Execução automática na inicialização
  • ✅ Idêntico em todos os ambientes
  • ✅ Impossível esquecer uma migração

2. Instalação​

Dependência Maven​

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

<!-- Para PostgreSQL, adicione também: -->
<dependency>
<groupId>org.flywaydb</groupId>
<artifactId>flyway-database-postgresql</artifactId>
</dependency>

Com Spring Boot​

É só isso! O Spring Boot auto-configura o Flyway automaticamente.

# application.properties
spring.flyway.enabled=true # Padrão: true se Flyway estiver no classpath

3. Estrutura de Arquivos​

Localização Padrão​

src/
└── main/
└── resources/
└── db/
└── migration/
├── V1__create_users_table.sql
├── V2__add_email_column.sql
├── V3__create_orders_table.sql
└── V4__add_index_on_email.sql

Convenção de Nomenclatura​

V{version}__{description}.sql
│ │ │
│ │ └── Descrição (underscores = espaços)
│ └── Número da versão (1, 2, 2.1, etc.)
└── Prefixo "V" (Migration versionada)

Exemplos válidos:

V1__create_users.sql
V2__add_email_to_users.sql
V2.1__add_phone_number.sql
V10__create_products.sql
V100__final_cleanup.sql

Exemplos inválidos:

V1_create_users.sql       ❌ Apenas um underscore
v1__create_users.sql ❌ Minúsculo
1__create_users.sql ❌ Sem prefixo V
V1__create users.sql ❌ Espaços no nome

4. Criando Migrações​

Migração 1: Criar uma Tabela​

-- V1__create_users_table.sql

CREATE TABLE users (
id BIGSERIAL PRIMARY KEY,
username VARCHAR(50) NOT NULL UNIQUE,
password VARCHAR(100) NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

Migração 2: Adicionar uma Coluna​

-- V2__add_email_to_users.sql

ALTER TABLE users
ADD COLUMN email VARCHAR(100) UNIQUE;

Migração 3: Criar Outra Tabela com FK​

-- V3__create_orders_table.sql

CREATE TABLE orders (
id BIGSERIAL PRIMARY KEY,
user_id BIGINT NOT NULL REFERENCES users(id),
total_amount DECIMAL(10, 2) NOT NULL,
status VARCHAR(20) DEFAULT 'PENDING',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

CREATE INDEX idx_orders_user_id ON orders(user_id);

Migração 4: Inserir Dados​

-- V4__insert_initial_data.sql

INSERT INTO users (username, password, email) VALUES
('admin', '$2a$10$hashedpassword', 'admin@example.com'),
('user1', '$2a$10$hashedpassword', 'user1@example.com');

5. Como o Flyway Funciona​

A Tabela flyway_schema_history​

Flyway cria automaticamente uma tabela para rastrear as migrações:

SELECT * FROM flyway_schema_history;
installed_rankversiondescriptiontypescriptchecksuminstalled_onexecution_timesuccess
11create users tableSQLV1__create_users_table.sql-1234562025-01-15 10:0045true
22add email to usersSQLV2__add_email_to_users.sql7890122025-01-15 10:0112true
33create orders tableSQLV3__create_orders_table.sql3456782025-01-16 09:0067true

Fluxo de Execução​


6. Configuração Spring Boot​

Configuração Básica​

# application.properties

# Ativar Flyway
spring.flyway.enabled=true

# Localização dos scripts (padrão: classpath:db/migration)
spring.flyway.locations=classpath:db/migration

# Baseline (para bancos já existentes)
spring.flyway.baseline-on-migrate=false
spring.flyway.baseline-version=1

Configuração Avançada​

# Schema alvo
spring.flyway.schemas=public

# Limpeza (PERIGOSO em produção!)
spring.flyway.clean-disabled=true

# Validação
spring.flyway.validate-on-migrate=true

# Substituição de placeholders
spring.flyway.placeholder-replacement=true
spring.flyway.placeholders.table_prefix=app_

Configuração YAML​

spring:
flyway:
enabled: true
locations: classpath:db/migration
baseline-on-migrate: false
clean-disabled: true
validate-on-migrate: true

7. Migrações Repetíveis​

Caso de Uso​

Certos objetos precisam ser recriados a cada alteração:

  • Views (CREATE OR REPLACE VIEW)
  • Procedures
  • Funções
  • Dados de referência

Convenção​

R__{description}.sql
│
└── Prefixo "R" (Repeatable)

Exemplo​

-- R__create_active_users_view.sql

CREATE OR REPLACE VIEW active_users AS
SELECT id, username, email
FROM users
WHERE last_login > NOW() - INTERVAL '30 days';

Comportamento:

  • Flyway calcula um checksum do arquivo
  • Se o arquivo mudar → reexecuta
  • Executado APÓS todas as migrações versionadas

8. Gerenciamento de Ambientes​

Estrutura Multi-Ambiente​

src/main/resources/
├── db/
│ └── migration/
│ ├── V1__create_tables.sql # Todos os ambientes
│ ├── V2__add_columns.sql
│ └── V3__create_indexes.sql
│
├── db-dev/
│ └── migration/
│ └── V1000__dev_test_data.sql # Dados de teste (apenas dev)
│
└── db-prod/
└── migration/
└── V1001__prod_config.sql # Configuração produção

Configuração por Perfil​

# application-dev.properties
spring.flyway.locations=classpath:db/migration,classpath:db-dev/migration

# application-prod.properties
spring.flyway.locations=classpath:db/migration,classpath:db-prod/migration

9. Integração com JPA/Hibernate​

Ordem de Execução​

# IMPORTANTE: Flyway executa ANTES do Hibernate
spring.jpa.hibernate.ddl-auto=validate # Não gerar schema

# Ou para dev:
spring.jpa.hibernate.ddl-auto=none # Flyway gerencia tudo

Workflow Recomendado​

dica

Em desenvolvimento: Use ddl-auto=validate para verificar se suas entidades correspondem ao schema.

Em produção: Use ddl-auto=none e deixe o Flyway gerenciar tudo.


10. Comandos Flyway​

Via Maven Plugin​

<plugin>
<groupId>org.flywaydb</groupId>
<artifactId>flyway-maven-plugin</artifactId>
<configuration>
<url>jdbc:postgresql://localhost:5432/mydb</url>
<user>postgres</user>
<password>secret</password>
</configuration>
</plugin>
# Ver migrações aplicadas
mvn flyway:info

# Aplicar migrações
mvn flyway:migrate

# Validar migrações
mvn flyway:validate

# Reparar histórico (atenção!)
mvn flyway:repair

# Limpar o banco (PERIGOSO!)
mvn flyway:clean

Exemplo de Saída flyway:info​

+-----------+---------+----------------------+------+---------------------+---------+
| Category | Version | Description | Type | Installed On | State |
+-----------+---------+----------------------+------+---------------------+---------+
| Versioned | 1 | create users table | SQL | 2025-01-15 10:00:00 | Success |
| Versioned | 2 | add email to users | SQL | 2025-01-15 10:01:00 | Success |
| Versioned | 3 | create orders table | SQL | 2025-01-16 09:00:00 | Success |
| Versioned | 4 | add indexes | SQL | | Pending |
+-----------+---------+----------------------+------+---------------------+---------+

11. Problemas Comuns e Soluções​

❌ Checksum Mismatch​

FlywayException: Validate failed: Migration checksum mismatch for migration version 2
-> Applied to database : -123456
-> Resolved locally : 789012

Causa: O arquivo de migração foi alterado após sua execução.

Soluções:

  1. Nunca modifique uma migração já executada!
  2. Se for em dev: mvn flyway:repair
  3. Crie uma nova migração para corrigir

❌ Migration Not Found​

FlywayException: Detected resolved migration not applied to database: 3

Causa: Uma migração existe no banco mas não nos arquivos.

Solução: Restaure o arquivo de migração ausente.

❌ Out of Order Migration​

FlywayException: Detected resolved migration not applied to database: 2
(Applied migrations are: 1, 3)

Causa: Migração V2 adicionada após V3.

Solução:

spring.flyway.out-of-order=true  # Permitir migrações fora de ordem

❌ Failed Migration​

FlywayException: Migration V4__add_index.sql failed

Solução:

  1. Corrija o SQL no arquivo
  2. Execute mvn flyway:repair (marca como resolvido)
  3. Execute mvn flyway:migrate

12. Boas Práticas​

✅ Regras de Ouro​

1. NUNCA modifique uma migração já executada
→ Crie uma nova migração para corrigir

2. NUNCA exclua uma migração executada
→ O histórico deve permanecer consistente

3. SEMPRE teste as migrações em um ambiente de teste
→ Antes de fazer deploy em produção

4. SEMPRE tenha um backup antes de migrar em produção
→ Por precaução

5. Mantenha as migrações pequenas e focadas
→ Uma migração = uma alteração lógica

✅ Nomenclatura Clara​

-- ✅ BOM
V1__create_users_table.sql
V2__add_email_column_to_users.sql
V3__create_orders_with_foreign_keys.sql

-- ❌ RUIM
V1__changes.sql
V2__update.sql
V3__fix.sql

✅ Scripts Idempotentes​

-- ✅ BOM: Verifica antes de criar
CREATE TABLE IF NOT EXISTS users (...);

-- ✅ BOM: Verifica antes de adicionar coluna (PostgreSQL)
DO $$
BEGIN
IF NOT EXISTS (SELECT 1 FROM information_schema.columns
WHERE table_name = 'users' AND column_name = 'phone') THEN
ALTER TABLE users ADD COLUMN phone VARCHAR(20);
END IF;
END $$;

13. Resumo​

Pontos-Chave​

ConceitoDescrição
FlywayFerramenta de migração de esquema versionado
V{n}__Prefixo para migrações versionadas
R__Prefixo para migrações repetíveis
flyway_schema_historyTabela que rastreia as migrações
checksumHash do arquivo para detectar alterações

Workflow Típico​

1. Criar um arquivo V{n}__description.sql
2. Escrever o SQL
3. Iniciar a aplicação (ou mvn flyway:migrate)
4. Flyway executa automaticamente
5. Verificar com mvn flyway:info

Configuração Mínima​

# Spring Boot + Flyway
spring.flyway.enabled=true
spring.flyway.locations=classpath:db/migration
spring.jpa.hibernate.ddl-auto=validate

🎯 Próximo Passo​

Flyway é a ferramenta mais popular, mas Liquibase oferece uma alternativa com funcionalidades diferentes. Vamos ver quando escolher uma ou outra.

➡️ Capítulo 4: Migração com Liquibase


⬅️ Voltar ao Módulo 7