Migrações de banco de dados em C++: visão geral de ferramentas e bibliotecas

Treinador Online de Python para Iniciantes

Aprenda Python facilmente sem sobrecarga teórica. Resolva tarefas práticas com verificação automática e escreva código diretamente no navegador.

Start Course

Migrações de banco de dados em C++: gerenciamento de esquema e versionamento

Em projetos C++ modernos que trabalham com bancos de dados relacionais (PostgreSQL, MySQL, SQLite), o suporte à evolução do esquema é uma prática obrigatória. As migrações permitem aplicar automaticamente alterações na estrutura de tabelas, índices e restrições, preservando a integridade dos dados entre as versões da aplicação. Ao contrário das linguagens dinâmicas, o C++ não possui uma ferramenta embutida para migrações, mas existem várias bibliotecas maduras que resolvem esse problema.



Requisitos principais para uma biblioteca de migrações para C++

  • Versionamento: cada migração deve ter um identificador único (numérico ou carimbo de data/hora).
  • Suporte a reversão: capacidade de aplicar operações "up" (criação/alteração) e "down" (remoção/reversão).
  • Integração com SGBD: funcionamento através de drivers padrão (libpq, sqlite3, MySQL Connector).
  • Transacionalidade: cada migração é executada em uma transação separada para atomicidade.
  • Aplicação automática: utilitário de linha de comando ou API para execução na inicialização da aplicação.


Ferramentas populares para migrações em C++

1. cpp-migrations (recomendado)

Biblioteca leve de código aberto, com suporte a PostgreSQL, MySQL, SQLite. As migrações são descritas como classes C++ com os métodos up() e down(). A versão é fixada no arquivo migrations.json.

// Exemplo de migração para cpp-migrations#include <migration.hpp>

class CreateUsersTable : public Migration {public: void up() override { execute("CREATE TABLE users (" "id SERIAL PRIMARY KEY," "name VARCHAR(100) NOT NULL," "email VARCHAR(255) UNIQUE," "created_at TIMESTAMP DEFAULT NOW()" ")"); }

void down() override { execute("DROP TABLE IF EXISTS users"); }};

REGISTER_MIGRATION(CreateUsersTable, "001_create_users");

Execução de migrações via API:

#include <migration_runner.hpp>

int main() { MigrationRunner runner("postgresql://user:pass@localhost/db"); runner.applyPending(); // aplica todas as migrações pendentes return 0;}


2. Migrações baseadas em libpq (abordagem personalizada)

Se o projeto já utiliza libpq (cliente nativo do PostgreSQL), é possível implementar um gerenciador de migrações simples baseado em arquivos SQL. Exemplo de estrutura:

migrations/├── 001_create_users.sql├── 001_create_users.down.sql├── 002_add_role_column.sql└── 002_add_role_column.down.sql

Código do carregador em C++:

#include <pqxx/pqxx>#include <filesystem>#include <fstream>

void applyMigrations(pqxx::connection &conn) { pqxx::work txn(conn); // Cria tabela para rastrear migrações aplicadas txn.exec("CREATE TABLE IF NOT EXISTS _migrations (" "id SERIAL PRIMARY KEY," "name TEXT UNIQUE," "applied_at TIMESTAMP DEFAULT NOW())"); for (const auto &entry : std::filesystem::directory_iterator("migrations")) { std::string filename = entry.path().filename().string(); if (filename.find(".down.") != std::string::npos) continue; if (filename.find(".sql") == std::string::npos) continue; // Verifica se a migração já foi aplicada auto check = txn.exec_params("SELECT 1 FROM _migrations WHERE name = $1", filename); if (check.empty()) { std::ifstream file(entry.path()); std::string sql((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>()); txn.exec(sql); txn.exec_params("INSERT INTO _migrations (name) VALU

Recommendations