Migrations de bases de données en C++ : aperçu des outils et bibliothèques

Formateur Python en ligne pour débutants

Apprenez Python facilement sans surcharge théorique. Résolvez des tâches pratiques avec vérification automatique et écrivez du code directement dans le navigateur.

Start Course

Migrations de bases de données en C++ : gestion de schéma et versionnement

Dans les projets C++ modernes travaillant avec des bases de données relationnelles (PostgreSQL, MySQL, SQLite), la prise en charge de l'évolution du schéma est une pratique obligatoire. Les migrations permettent d'appliquer automatiquement les modifications de structure des tables, des index et des contraintes, tout en préservant l'intégrité des données entre les versions de l'application. Contrairement aux langages dynamiques, C++ ne dispose pas d'outil intégré pour les migrations, mais il existe plusieurs bibliothèques matures qui résolvent ce problème.



Exigences principales pour une bibliothèque de migrations en C++

  • Versionnement : chaque migration doit avoir un identifiant unique (numérique ou horodatage).
  • Prise en charge du rollback : possibilité d'appliquer les opérations "up" (création/modification) et "down" (suppression/rollback).
  • Intégration avec le SGBD : fonctionnement via les pilotes standards (libpq, sqlite3, MySQL Connector).
  • Transactionalité : chaque migration est exécutée dans une transaction distincte pour l'atomicité.
  • Application automatique : utilitaire en ligne de commande ou API pour lancer au démarrage de l'application.


Outils populaires pour les migrations en C++

1. cpp-migrations (recommandé)

Bibliothèque légère open source, prenant en charge PostgreSQL, MySQL, SQLite. Les migrations sont décrites sous forme de classes C++ avec les méthodes up() et down(). La version est fixée dans le fichier migrations.json.

// Exemple de migration pour 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");

Lancement des migrations via l'API :

#include <migration_runner.hpp>

int main() { MigrationRunner runner("postgresql://user:pass@localhost/db"); runner.applyPending(); // applique toutes les migrations non appliquées return 0;}


2. Migrations basées sur libpq (approche personnalisée)

Si le projet utilise déjà libpq (client natif PostgreSQL), on peut implémenter un gestionnaire de migrations simple basé sur des fichiers SQL. Exemple de structure :

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

Code du chargeur en C++ :

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

void applyMigrations(pqxx::connection &conn) { pqxx::work txn(conn); // Création de la table pour suivre les migrations appliquées 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; // Vérification si la migration est déjà appliquée 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