Estratégias de deploy de schema com migrations reversíveis
1. Fundamentos das Migrations Reversíveis
Migrations são scripts que alteram a estrutura do banco de dados ao longo do tempo. Uma migration reversível contém duas direções: up() (aplica a mudança) e down() (desfaz a mudança). Em ambientes de produção, a reversibilidade não é opcional — é uma necessidade operacional.
-- Exemplo de migration reversível (SQL)
-- Migration: adicionar coluna email_verified
-- UP
ALTER TABLE usuarios ADD COLUMN email_verified BOOLEAN DEFAULT FALSE;
-- DOWN
ALTER TABLE usuarios DROP COLUMN email_verified;
A diferença entre rollback automático e manual é crítica: ferramentas como Flyway ou Liquibase permitem rollback automático desde que o down() esteja bem definido. Rollback manual é arriscado e deve ser evitado em produção.
2. Modelagem de Migrations com Reversão Segura
Cada migration deve seguir uma estrutura padrão com up() e down(). A regra de ouro para o down() é: nunca perder dados permanentemente.
-- Migration v1.1: adicionar tabela de endereços
-- UP
CREATE TABLE enderecos (
id SERIAL PRIMARY KEY,
usuario_id INTEGER NOT NULL REFERENCES usuarios(id),
rua VARCHAR(200),
cidade VARCHAR(100),
criado_em TIMESTAMP DEFAULT NOW()
);
-- DOWN
-- Backup antes de dropar
CREATE TABLE enderecos_backup_v1_1 AS SELECT * FROM enderecos;
DROP TABLE enderecos;
Versionamento semântico de schemas (v1.0, v1.1, v2.0) ajuda a rastrear mudanças e planejar reversões complexas.
3. Estratégias de Deploy em Múltiplos Ambientes
Um pipeline típico de deploy de schema segue: dev → staging → produção. Cada ambiente deve ter seu próprio conjunto de migrations versionadas.
# Estrutura de branches para migrations
main/
├── migrations/
│ ├── v1.0_initial.sql
│ ├── v1.1_add_enderecos.sql
│ └── v1.2_add_telefone.sql
# Tags para controle de versão
git tag v1.0-staging
git tag v1.0-production
git tag v1.1-staging
Testes automatizados de reversão são obrigatórios antes de qualquer deploy em produção:
# Script de teste de reversão (exemplo conceitual)
1. Aplicar migration v1.1 em staging
2. Verificar integridade dos dados
3. Executar rollback para v1.0
4. Verificar se dados foram preservados
5. Repetir o ciclo 3 vezes
4. Técnicas de Reversão Parcial e Total
Reversão de uma única migration (rollback específico):
-- Reverter apenas a migration v1.2
-- Executar apenas o down() da v1.2
ALTER TABLE usuarios DROP COLUMN telefone;
Reversão em lote (rollback de múltiplas versões):
-- Reverter da v1.3 para v1.0
-- Executar down() da v1.3
-- Executar down() da v1.2
-- Executar down() da v1.1
Reversão com validação de integridade referencial:
-- Verificar chaves estrangeiras antes de dropar tabela
SELECT COUNT(*) FROM enderecos WHERE usuario_id NOT IN (SELECT id FROM usuarios);
-- Se zero, pode dropar com segurança
5. Gerenciamento de Dados Durante Reversões
Preservação de dados críticos em down() é feita com backup temporário:
-- Estratégia de backup em down()
CREATE TABLE backup_usuarios_telefone AS
SELECT id, telefone FROM usuarios;
ALTER TABLE usuarios DROP COLUMN telefone;
Para colunas com valores default ou nulos:
-- UP: adicionar coluna com default
ALTER TABLE usuarios ADD COLUMN plano VARCHAR(20) DEFAULT 'basico';
-- DOWN: preservar dados antes de dropar
UPDATE usuarios SET plano = NULL WHERE plano = 'basico';
ALTER TABLE usuarios DROP COLUMN plano;
Reversão com migração de dados (transformação de tipos):
-- UP: mudar tipo de coluna
ALTER TABLE usuarios ALTER COLUMN idade TYPE VARCHAR(3);
-- DOWN: converter de volta com validação
UPDATE usuarios SET idade = CAST(idade AS INTEGER)::TEXT
WHERE idade ~ '^\d+$';
ALTER TABLE usuarios ALTER COLUMN idade TYPE INTEGER USING idade::INTEGER;
6. Ferramentas e Frameworks de Suporte
Flyway (Java/Spring):
-- Configuração de migration reversível no Flyway
-- Arquivo: V1_1__add_email_verified.sql
-- UP
ALTER TABLE usuarios ADD COLUMN email_verified BOOLEAN;
-- Arquivo: U1_1__add_email_verified.sql (undo)
-- DOWN
ALTER TABLE usuarios DROP COLUMN email_verified;
Liquibase (XML/YAML/JSON):
-- changeset.xml
<changeSet id="1" author="dev">
<addColumn tableName="usuarios">
<column name="email_verified" type="BOOLEAN"/>
</addColumn>
<rollback>
<dropColumn tableName="usuarios" columnName="email_verified"/>
</rollback>
</changeSet>
Alembic (Python):
# migration.py
def upgrade():
op.add_column('usuarios', sa.Column('email_verified', sa.Boolean()))
def downgrade():
op.drop_column('usuarios', 'email_verified')
ActiveRecord (Rails):
class AddEmailVerifiedToUsuarios < ActiveRecord::Migration[7.0]
def change
add_column :usuarios, :email_verified, :boolean, default: false
end
end
Hooks de pré e pós-migration:
# Hook pré-migration: backup automático
before_migration:
- pg_dump -U user -d database > backup_$(date +%Y%m%d).sql
# Hook pós-migration: validação
after_migration:
- python validate_schema.py
7. Casos Complexos e Armadilhas Comuns
Reversão de migrations com índices ou constraints únicas:
-- UP: adicionar índice único
CREATE UNIQUE INDEX idx_email_unique ON usuarios(email);
-- DOWN: remover índice
DROP INDEX IF EXISTS idx_email_unique;
-- Cuidado: se houver duplicatas, o índice não pode ser recriado depois
Dependências entre migrations:
-- Migration v1.1: criar tabela dependente
CREATE TABLE pedidos (id SERIAL PRIMARY KEY, usuario_id INTEGER REFERENCES usuarios(id));
-- Migration v1.2: adicionar coluna em usuarios
ALTER TABLE usuarios ADD COLUMN ultimo_pedido_id INTEGER REFERENCES pedidos(id);
-- Ordem de reversão: v1.2 primeiro, depois v1.1
Reversão em sistemas com alta concorrência:
-- Usar lock de tabela durante reversão
LOCK TABLE usuarios IN ACCESS EXCLUSIVE MODE;
ALTER TABLE usuarios DROP COLUMN email_verified;
-- Libera lock automaticamente ao final da transação
8. Boas Práticas e Checklist Final
- [ ] Revisão de código de
down()por pares: outro desenvolvedor deve validar se o rollback não perde dados - [ ] Testes de estresse com reversões em staging: execute rollback e forward 10 vezes seguidas
- [ ] Documentação de cada migration: inclua justificativa da reversão e riscos conhecidos
# Template de documentação de migration
Migration: v1.1_add_email_verified
Autor: João Silva
Data: 2024-01-15
Descrição: Adiciona flag de verificação de email
Justificativa de reversão: Se houver problemas de performance na consulta
Riscos: Perda de dados se usuários já estiverem verificados
Checklist final antes do deploy em produção:
- Backup completo do banco antes de qualquer migration
- Teste de reversão em staging com dados similares à produção
- Monitoramento de logs durante a execução
- Plano de contingência para rollback manual se automático falhar
- Comunicação à equipe sobre a janela de manutenção
Referências
- Flyway Documentation - Undo Migrations — Documentação oficial sobre migrations reversíveis com Flyway, incluindo configuração de arquivos de undo
- Liquibase Rollback Documentation — Guia completo de rollback no Liquibase, com exemplos de changesets reversíveis
- Alembic - Migration Reversibility — Tutorial oficial do Alembic mostrando como criar migrations com upgrade e downgrade
- Rails ActiveRecord Migrations Guide — Guia oficial do Rails sobre migrations, incluindo reversão e rollback
- PostgreSQL Documentation - ALTER TABLE — Referência oficial sobre comandos DDL no PostgreSQL, essencial para escrever migrations seguras
- Martin Fowler - Evolutionary Database Design — Artigo clássico sobre design evolutivo de banco de dados, abordando estratégias de migrations reversíveis
- AWS Database Migration Service Best Practices — Práticas recomendadas da AWS para migrações de banco de dados, incluindo reversão em ambientes cloud