Versionskontrollsysteme und insbesondere Git sind wichtige Tools zum Verfolgen von Codeänderungen, zur Zusammenarbeit mit Ihrem Team und zur Gewährleistung der Stabilität Ihrer Codebasis. Während Git in erster Linie für Quellcode konzipiert ist, können Sie es auch in Kombination mit MySQL- Datenbanken zur Versionskontrolle und Schema-Änderungsverwaltung verwenden.
In diesem Artikel untersuchen wir anhand spezifischer Beispiele in einem Leitfadenformat, wie man Git mit MySQL zur Versionskontrolle mithilfe von Git-Hooks integriert. Alle in den Auflistungen aufgeführten Skripte sind voll funktionsfähig und vollständig. Sie können sie sequentiell in Ihrer Testumgebung reproduzieren.
Erstellen wir zunächst eine Testdatenbank und einen Benutzer:
create database testdb_remote; create user 'user_remote'@'localhost' identified WITH mysql_native_password by 'remote123'; grant all on testdb_remote.* to 'user_remote'@'localhost';
Als nächstes erstellen wir ein Remote-Repository. Dies kann ein Repository auf einem beliebigen Remote-Server sein, der Einfachheit halber erstellen wir es jedoch lokal. Um die Ausführung von Befehlen zu vereinfachen, verwende ich Git Bash. Mein lokaler Computer verfügt bereits über einen Git-Ordner, also verwende ich ihn:
cd /c/git mkdir testdb.remote cd testdb.remote git init --bare
Und erstellen Sie ein lokales Repository als Klon des Remote-Repositorys:
cd /c/git git clone /c/git/testdb.remote testdb.local cd testdb.local git ls-files
Es sind keine Dateien im Repository vorhanden; Lassen Sie uns eines erstellen und unsere Änderungen in das Remote-Repository übertragen:
echo "Test DB repo" > readme.md git status git add . git commit -m "1st commit" git push
Lassen Sie uns den Inhalt des Remote-Repositorys überprüfen:
cd /c/git/testdb.remote git ls-tree --full-tree -r HEAD
Im Remote-Repository gibt es einen Hooks-Ordner, der mehrere Dateien mit Beispielen enthält:
ls -1 /c/git/testdb.remote/hooks
Hooks sind Skripte, die ausgeführt werden, wenn bestimmte Ereignisse eintreten. Git verfügt über clientseitige und serverseitige Hooks. Clientseitige Hooks werden durch Vorgänge wie Festschreiben und Zusammenführen ausgelöst. Serverseitige Hooks werden bei Netzwerkvorgängen wie dem Empfang von Push-Commits ausgeführt. Haken werden hier ausführlich beschrieben. Für die Umsetzung der Logik gibt es verschiedene Möglichkeiten; Ich gebe ein Beispiel für die Verwendung des serverseitigen Post-Receive -Hooks.
Im Hooks-Ordner müssen wir eine Datei mit dem Namen „post-receive“ erstellen. Dies ist ein normales Bash-Skript:
#!/bin/sh while read oval nval ref do echo List of files changed in the commit: git diff --name-only $oval $nval done
Das obige Skript wird auf dem Server ausgeführt, wenn ein Push erfolgreich abgeschlossen wurde, und gibt eine Liste der geänderten Dateien aus. Lassen Sie uns überprüfen, wie es funktioniert, indem wir eine Zeile zur readme.md hinzufügen und die Änderungen an das Remote-Repository übertragen:
cd /c/git/testdb.local echo "New line" >> readme.md git add . git commit -m "Line added" git push
Sie können sehen, dass beim Ausführen des Befehls „git push“ die Ausgabe jetzt Zeilen enthält, die mit remote:
– Dies ist die Ausgabe des Post-Receive-Skripts, das auf dem Server ausgeführt wurde.
Apropos grundlegende Änderungen: Dateien können hinzugefügt, geändert und gelöscht werden. Sie können verschiedene Ansätze verfolgen, um diese Änderungen auf die Datenbank anzuwenden:
Angenommen, Sie haben die zweite Option gewählt, sodass Sie hinzugefügte oder geänderte Dateien ausführen müssen. Wir können solche Dateien wie hier beschrieben filtern, indem wir den Parameter --diff-filter=AM
hinzufügen:
#!/bin/sh while read oval nval ref do echo List of files added or changed in the commit: git diff --name-only --diff-filter=AM $oval $nval done
Fügen Sie ein paar Dateien hinzu und ändern Sie auch die Datei readme.md erneut:
echo "SELECT 1;" > test1.sql echo "SELECT 2;" > test2.sql echo "SELECT 3;" > test3.sql echo "New line 2" >> readme.md git add . git commit -m "New files" git push
Die Ausgabe des Hook-Skripts enthält 4 Dateien:
Wir bearbeiten die Dateien test1.sql und readme.md, löschen test2.sql und fügen eine weitere Datei hinzu:
echo "SELECT 11;" > test1.sql echo "New line 2" >> readme.md rm test2.sql echo "SELECT 4;" > test4.sql git add . git commit -m "Modify, remove and add" git push
Es werden nur geänderte und hinzugefügte Dateien angezeigt:
Unser Ziel ist es, nach jedem erfolgreichen Push SQL-Skripte auszuführen, daher müssen wir nur Dateien dieses Typs filtern; In unserem Fall legen wir die Anforderung fest, dass sie alle die Erweiterung „.sql“ haben müssen. Fügen Sie zum Filtern den Parameter -- "*.sql"
zum Befehl git diff
hinzu:
#!/bin/sh while read oval nval ref do echo List of files added or changed in the commit: git diff --name-only --diff-filter=AM $oval $nval -- "*.sql" done
Um Skripte auszuführen, müssen wir auch eine Verbindung zur Datenbank herstellen können. Dazu erstellen wir Zugangsdaten und testen die Verbindung:
mysql_config_editor set --login-path=testdb_remote --host=localhost --port=3306 --user=user_remote --password mysql --login-path=testdb_remote --database=testdb_remote
Ändern Sie unser Skript, um die „.sql“-Dateien zu durchlaufen, jede Datei auszuführen und das Ergebnis zu überprüfen. Wir müssen auch die Listenausgabe sortieren, um die Dateien in der erforderlichen Reihenfolge auszuführen. Mit dem Befehl git show zeigen wir den Inhalt des SQL-Skripts an und leiten es zur Ausführung durch MySQL durch die Pipe .
Die Variable „$?“ enthält 0, wenn das SQL-Skript erfolgreich ausgeführt wurde, und einen anderen Wert, wenn ein Fehler aufgetreten ist:
#!/bin/sh while read oval nval ref do echo List of files added or changed in the commit: for file in $(git diff --name-only --diff-filter=AM $oval $nval -- "*.sql" | sort); do git show master:${file} | mysql --login-path=testdb_remote --database=testdb_remote echo "FILE: ${file} - result $?" done done
Führen Sie einen weiteren Test durch – löschen Sie alle zuvor erstellten „.sql“-Dateien und erstellen Sie Skripte für:
Außerdem müssen wir jedem Dateinamen ein Präfix (1_, 2_ usw.) hinzufügen, um die gewünschte Ausführungsreihenfolge der Dateien sicherzustellen:
rm *.sql echo "DB Initialization" >> readme.md echo " DROP TABLE IF EXISTS customers; CREATE TABLE customers ( id int UNSIGNED NOT NULL AUTO_INCREMENT, name varchar(255) DEFAULT NULL, PRIMARY KEY (id) ); " > 1_customers.sql echo " INSERT INTO customers (id, name) VALUES (1, 'John Doe'), (2, 'Jane Smith') AS new ON DUPLICATE KEY UPDATE customers.name = new.name; " > 2_customers_init.sql echo " DROP PROCEDURE IF EXISTS get_customer; DELIMITER $$ CREATE PROCEDURE get_customer(IN customer_id int UNSIGNED) BEGIN SELECT c.id, c.name FROM customers c WHERE c.id = customer_id; END $$ " > 3_get_customer.sql echo "SELECT FROM customers;" > 4_error_select.sql ls -1
Wir haben also vier „.sql“-Dateien, die ausgeführt werden müssen:
Wir nehmen Änderungen am Repository vor:
Und wir sehen, dass beim Ausführen git push
die Dateien nacheinander ausgeführt werden und das Ausführungsergebnis (MySQL-Befehls-Exit-Code) jeder Datei angezeigt wird. Die Datei „4_error_select.sql“ enthält einen Syntaxfehler, daher ist das Ergebnis ihrer Ausführung 1.
Und zum Schluss überprüfen wir, was wir in der Datenbank haben:
mysql --login-path=testdb_remote --database=testdb_remote show tables; call get_customer(1); call get_customer(2);
Wie Sie sehen, wurden die Tabelle und die Prozedur in der Remote-Datenbank erstellt. Die Prozedur wird erfolgreich ausgeführt und gibt Daten zurück.
Um die Lesbarkeit der Hook-Skript-Ausgabe zu verbessern, können Sie die MySQL-CLI-Ausgabe unterdrücken oder in eine Protokolldatei umleiten. Sie können auch das Ergebnis der MySQL-Befehlsausführung analysieren und dem Hook-Skript weitere Logik hinzufügen.
Sie können beispielsweise SQL-Skripte auf einer Testdatenbank ausführen und dann einige Tests darauf ausführen (wie ich hier beschrieben habe). Wenn die Tests in der Testdatenbank erfolgreich abgeschlossen wurden, führen Sie SQL-Skripte in der Produktionsdatenbank aus und führen Sie wahrscheinlich auch einige Tests darin aus.
Durch die Analyse der Ergebnisse jedes Schritts können Sie Pipelines beliebiger Konfiguration erstellen.
Natürlich hat jeder Ansatz eine Reihe von Vorteilen und Einschränkungen. Beim zweiten Ansatz ist es notwendig, die Reihenfolge sicherzustellen, in der die Skripte ausgeführt werden, da wir beispielsweise keine Daten in eine Tabelle einfügen können, bevor diese erstellt wurde. Es muss außerdem sichergestellt werden, dass Sie Skripte erneut ausführen können, d. h. Situationen korrekt behandeln können, in denen sich das zu erstellende Objekt bereits in der Datenbank befindet oder die Datenbank bereits die hinzuzufügenden Daten enthält.
Bei Verwendung eines Versionierungssystems wird der Entwicklungsprozess etwas komplizierter, da Änderungen in Skripten eines vorgegebenen Formats zusätzlich formalisiert werden müssen. Durch die Verwendung einer Installationsdatei können Sie jedoch eine gewisse Flexibilität erreichen.
Der Hauptvorteil der beschriebenen Technik ist die Implementierung der Versionierung in der Datenbank mit sehr geringem Aufwand sowie die Möglichkeit , CI/CD-Pipelines zu implementieren.
Um zu beurteilen, ob dies für Sie nützlich sein könnte, können Sie sich zunächst fragen: Wie oft schreiben Sie Code direkt in der Produktion?