Datenbankmigrationen in C++: Schemaverwaltung und Versionierung
In modernen C++-Projekten, die mit relationalen Datenbanken (PostgreSQL, MySQL, SQLite) arbeiten, ist die Unterstützung der Schema-Evolution eine zwingende Praxis. Migrationen ermöglichen es, Änderungen an Tabellenstrukturen, Indizes und Constraints automatisch anzuwenden und dabei die Datenintegrität zwischen verschiedenen Versionen der Anwendung zu wahren. Im Gegensatz zu dynamischen Sprachen verfügt C++ über kein integriertes Tool für Migrationen, aber es gibt mehrere ausgereifte Bibliotheken, die diese Aufgabe lösen.
Grundlegende Anforderungen an eine Migrationsbibliothek für C++
- Versionierung: Jede Migration muss eine eindeutige Kennung (numerisch oder als Zeitstempel) haben.
- Rollback-Unterstützung: Möglichkeit, "up"- (Erstellung/Änderung) und "down"- (Löschung/Rollback) Operationen anzuwenden.
- Integration mit DBMS: Arbeit über Standardtreiber (libpq, sqlite3, MySQL Connector).
- Transaktionalität: Jede Migration wird in einer eigenen Transaktion zur Gewährleistung der Atomarität ausgeführt.
- Automatische Anwendung: Kommandozeilen-Dienstprogramm oder API zum Starten beim Anwendungsstart.
Beliebte Tools für Migrationen in C++
1. cpp-migrations (empfohlen)
Eine leichtgewichtige Open-Source-Bibliothek, die PostgreSQL, MySQL und SQLite unterstützt. Migrationen werden als C++-Klassen mit den Methoden up() und down() beschrieben. Die Version wird in der Datei migrations.json festgehalten.
// Beispiel einer Migration für 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");Starten von Migrationen über die API:
#include <migration_runner.hpp>
int main() { MigrationRunner runner("postgresql://user:pass@localhost/db"); runner.applyPending(); // wendet alle noch nicht angewendeten Migrationen an return 0;}2. libpq-basierte Migrationen (selbst geschriebener Ansatz)
Wenn das Projekt bereits libpq (den nativen PostgreSQL-Client) verwendet, kann ein einfacher Migrationsmanager auf Basis von SQL-Dateien implementiert werden. Beispielstruktur:
migrations/├── 001_create_users.sql├── 001_create_users.down.sql├── 002_add_role_column.sql└── 002_add_role_column.down.sqlLadecode in C++:
#include <pqxx/pqxx>#include <filesystem>#include <fstream>
void applyMigrations(pqxx::connection &conn) { pqxx::work txn(conn); // Erstelle eine Tabelle zur Nachverfolgung angewendeter Migrationen 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; // Prüfen, ob die Migration bereits angewendet wurde 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 Auch in der Bibliothek
PDF-Berichterstellung mit C# (.NET) mit iTextSharp und QuestPDF
Swift-QR-Code-Generator: Bibliothek EFQRCode für iOS und macOS
GraphQL für Swift: Apollo iOS — Client für iOS und macOS
ORM für Kotlin: Exposed vs Ktor vs Ktorm — Vergleich und Beispiele