Saltar al contenido principal

Capítulo 3: Migración de Esquema con Flyway

Introducción​

¿Alguna vez ha vivido esta situación?

"Espera, ¿qué script SQL ejecutó en producción?"
"El que tiene las nuevas columnas... ¿creo?"
"¡Pero había 3 versiones! ¿V1, V2 o V2_final_final?"
💀

Flyway resuelve este problema versionando su esquema de base de datos como versiona su código.


🎯 Objetivos del Capítulo​

Al final de este capítulo, usted sabrá:

  1. ✅ Por qué Flyway es esencial para producción
  2. ✅ Instalar y configurar Flyway con Spring Boot
  3. ✅ Crear scripts de migración
  4. ✅ Comprender la convención de nombres
  5. ✅ Gestionar migraciones repetibles
  6. ✅ Resolver problemas comunes

1. ¿Por qué versionar el esquema?​

El Problema​

Problemas:

  • No se sabe qué script se ha ejecutado
  • No hay historial
  • Riesgo de olvidar una migración
  • Imposible reproducir el entorno

La Solución: Flyway​

Ventajas:

  • ✅ Historial completo de migraciones
  • ✅ Ejecución automática al iniciar
  • ✅ Idéntico en todos los entornos
  • ✅ Imposible olvidar una migración

2. Instalación​

Dependencia Maven​

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

<!-- Para PostgreSQL, agregue también: -->
<dependency>
<groupId>org.flywaydb</groupId>
<artifactId>flyway-database-postgresql</artifactId>
</dependency>

Con Spring Boot​

¡Eso es todo! Spring Boot auto-configura Flyway automáticamente.

# application.properties
spring.flyway.enabled=true # Por defecto: true si Flyway está en el classpath

3. Estructura de Archivos​

Ubicación por Defecto​

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

Convención de Nombres​

V{version}__{description}.sql
│ │ │
│ │ └── Descripción (underscores = espacios)
│ └── Número de versión (1, 2, 2.1, etc.)
└── Prefijo "V" (Migración versionada)

Ejemplos 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

Ejemplos inválidos:

V1_create_users.sql       ❌ Solo un underscore
v1__create_users.sql ❌ Minúscula
1__create_users.sql ❌ Sin prefijo V
V1__create users.sql ❌ Espacios en el nombre

4. Crear Migraciones​

Migración 1: Crear una Tabla​

-- 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
);

Migración 2: Agregar una Columna​

-- V2__add_email_to_users.sql

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

Migración 3: Crear Otra Tabla con 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);

Migración 4: Insertar Datos​

-- 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. ¿Cómo funciona Flyway?​

La Tabla flyway_schema_history​

Flyway crea automáticamente una tabla para rastrear las migraciones:

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

Flujo de Ejecución​


6. Configuración Spring Boot​

Configuración Básica​

# application.properties

# Activar Flyway
spring.flyway.enabled=true

# Ubicación de los scripts (por defecto: classpath:db/migration)
spring.flyway.locations=classpath:db/migration

# Baseline (para bases de datos existentes)
spring.flyway.baseline-on-migrate=false
spring.flyway.baseline-version=1

Configuración Avanzada​

# Esquema objetivo
spring.flyway.schemas=public

# Limpieza (¡PELIGROSO en producción!)
spring.flyway.clean-disabled=true

# Validación
spring.flyway.validate-on-migrate=true

# Sustitución de placeholders
spring.flyway.placeholder-replacement=true
spring.flyway.placeholders.table_prefix=app_

Configuración YAML​

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

7. Migraciones Repetibles​

Casos de Uso​

Algunos objetos deben ser recreados en cada cambio:

  • Vistas (CREATE OR REPLACE VIEW)
  • Procedimientos almacenados
  • Funciones
  • Datos de referencia

Convención​

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

Ejemplo​

-- 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';

Comportamiento:

  • Flyway calcula un checksum del archivo
  • Si el archivo cambia → se reejecuta
  • Se ejecuta DESPUÉS de todas las migraciones versionadas

8. Gestión de Entornos​

Estructura Multi-Entorno​

src/main/resources/
├── db/
│ └── migration/
│ ├── V1__create_tables.sql # Todos los entornos
│ ├── V2__add_columns.sql
│ └── V3__create_indexes.sql
│
├── db-dev/
│ └── migration/
│ └── V1000__dev_test_data.sql # Datos de prueba (solo dev)
│
└── db-prod/
└── migration/
└── V1001__prod_config.sql # Configuración producción

Configuración 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. Integración con JPA/Hibernate​

Orden de Ejecución​

# IMPORTANTE: Flyway se ejecuta ANTES que Hibernate
spring.jpa.hibernate.ddl-auto=validate # No generar el esquema

# O para desarrollo:
spring.jpa.hibernate.ddl-auto=none # Flyway gestiona todo

Flujo de Trabajo Recomendado​

tip

En desarrollo: Utilice ddl-auto=validate para verificar que sus entidades correspondan al esquema.

En producción: Utilice ddl-auto=none y deje que Flyway gestione todo.


10. Comandos Flyway​

Vía 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 migraciones aplicadas
mvn flyway:info

# Aplicar migraciones
mvn flyway:migrate

# Validar migraciones
mvn flyway:validate

# Reparar el historial (¡cuidado!)
mvn flyway:repair

# Limpiar la base de datos (¡PELIGROSO!)
mvn flyway:clean

Ejemplo de Salida 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 Comunes y Soluciones​

❌ Checksum Mismatch​

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

Causa: El archivo de migración fue modificado después de su ejecución.

Soluciones:

  1. Nunca modificar una migración ya ejecutada.
  2. Si es en desarrollo: mvn flyway:repair
  3. Crear una nueva migración para corregir

❌ Migration Not Found​

FlywayException: Detected resolved migration not applied to database: 3

Causa: Existe una migración en la base de datos pero no en los archivos.

Solución: Restaurar el archivo de migración faltante.

❌ Out of Order Migration​

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

Causa: Migración V2 agregada después de V3.

Solución:

spring.flyway.out-of-order=true  # Permitir migraciones fuera de orden

❌ Failed Migration​

FlywayException: Migration V4__add_index.sql failed

Solución:

  1. Corregir el SQL en el archivo
  2. Ejecutar mvn flyway:repair (marca como resuelto)
  3. Ejecutar mvn flyway:migrate

12. Mejores Prácticas​

✅ Reglas de Oro​

1. NUNCA modificar una migración ya ejecutada
→ Crear una nueva migración para corregir

2. NUNCA eliminar una migración ejecutada
→ El historial debe permanecer coherente

3. SIEMPRE probar las migraciones en un entorno de pruebas
→ Antes de desplegar en producción

4. SIEMPRE tener un backup antes de migrar en producción
→ Por si acaso

5. Mantener las migraciones pequeñas y enfocadas
→ Una migración = una modificación lógica

✅ Nombres Claros​

-- ✅ BUENO
V1__create_users_table.sql
V2__add_email_column_to_users.sql
V3__create_orders_with_foreign_keys.sql

-- ❌ MALO
V1__changes.sql
V2__update.sql
V3__fix.sql

✅ Scripts Idempotentes​

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

-- ✅ BUENO: Verifica antes de agregar una columna (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. Resumen​

Puntos Clave​

ConceptoDescripción
FlywayHerramienta de migración de esquema versionado
V{n}__Prefijo para migraciones versionadas
R__Prefijo para migraciones repetibles
flyway_schema_historyTabla que rastrea las migraciones
checksumHash del archivo para detectar modificaciones

Flujo de Trabajo Típico​

1. Crear un archivo V{n}__description.sql
2. Escribir el SQL
3. Iniciar la aplicación (o mvn flyway:migrate)
4. Flyway ejecuta automáticamente
5. Verificar con mvn flyway:info

Configuración Mínima​

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

🎯 Próximo Paso​

Flyway es la herramienta más popular, pero Liquibase ofrece una alternativa con funcionalidades diferentes. Veamos cuándo elegir una u otra.

➡️ Capítulo 4: Migración con Liquibase


⬅️ Volver al Módulo 7