Es ist nie passiert, und hier ist es wieder!
Beim nächsten Projekt haben wir uns von Anfang an für den Einsatz von Liquibase entschieden, um zukünftige Probleme zu vermeiden. Wie sich herausstellte, wissen nicht alle jungen Teammitglieder, wie man es richtig nutzt. Ich habe einen internen Workshop durchgeführt, den ich dann in einen Artikel umgewandelt habe.
Dieser Artikel enthält hilfreiche Tipps und Beschreibungen der drei offensichtlichsten Fallstricke, auf die Sie bei der Arbeit mit relationalen Datenbankmigrationstools, insbesondere Liquibase, stoßen können. Entwickelt für Java-Entwickler der Junior- und Middle-Ebene, kann es für erfahrenere Entwickler interessant sein, um das zu strukturieren und zu wiederholen, was höchstwahrscheinlich bereits bekannt ist.

Liquibase und Flyway sind die wichtigsten konkurrierenden Technologien zur Lösung der Probleme der Versionskontrolle relationaler Strukturen in der Java-Welt. Ersteres ist völlig kostenlos, in der Praxis wird es häufiger verwendet, weshalb Liquibase zum Helden der Veröffentlichung gewählt wurde. Einige der beschriebenen Vorgehensweisen können jedoch je nach Architektur Ihrer Anwendung generisch sein.
Relationale Migrationen sind eine erzwungene Möglichkeit, mit der schwachen Flexibilität relationaler Datenspeicher umzugehen. Im Zeitalter der OOP-Mode bedeutete die Art der Arbeit mit der Datenbank, dass wir das Schema einmal beschrieben und es nicht noch einmal berührten. Die Realität sieht jedoch immer so aus, dass sich die Dinge ändern und häufig Änderungen an der Struktur von Tabellen erforderlich sind. Natürlich ist der Prozess selbst schmerzhaft und unangenehm.
Ich werde mich nicht mit der Beschreibung der Technologie und den Anweisungen zum Hinzufügen der Bibliothek zu Ihrem Projekt befassen, es wurden bereits genügend Artikel zu diesem Thema geschrieben:
Darüber hinaus gab es bereits einen tollen Artikel zum Thema nützliche Tipps:
Tipps
Ich möchte meine Ratschläge und Kommentare weitergeben, die durch den Schweiß, das Blut und den Schmerz bei der Lösung von Migrationsproblemen entstanden sind.
1. Bevor Sie beginnen, sollten Sie den Abschnitt „Best Practices“ lesen Liquidbase
Es werden einfache, aber sehr wichtige Dinge beschrieben, ohne die die Nutzung der Bibliothek Ihr Leben erschweren kann. Beispielsweise wird ein nicht-struktureller Ansatz für das Changeset-Management früher oder später zu Verwirrung und fehlerhaften Migrationen führen. Wenn Sie nicht gleichzeitig voneinander abhängige Änderungen in der Struktur der Datenbank und der Logik der Dienste einführen, ist die Wahrscheinlichkeit hoch, dass dies zu roten Tests oder einer kaputten Umgebung führt. Darüber hinaus enthalten die Empfehlungen zur Verwendung von Liquibase auf der offiziellen Website einen Absatz über die Entwicklung und Überprüfung von Rollback-Skripten sowie die wichtigsten Migrationsskripte. Nun, im Artikel Es gibt Beispiele für Code im Zusammenhang mit Migrationen und dem Rollback-Mechanismus.
2. Wenn Sie begonnen haben, Migrationstools zu verwenden, lassen Sie keine manuellen Korrekturen in der Datenbankstruktur zu
Wie das Sprichwort sagt: „Einmal Persil, immer Persil.“ Wenn die Basis Ihrer Anwendung nun von Liquibase-Tools verwaltet wird, führen alle manuellen Änderungen sofort zu einem inkonsistenten Zustand und das Vertrauen in die Änderungssätze geht auf Null zurück. Potenzielle Risiken – mehrere Stunden Zeitaufwand für die Wiederherstellung der Datenbank, im schlimmsten Fall ein toter Server. Wenn Ihr Team über einen DBA-Architekten der „alten Schule“ verfügt, erklären Sie ihm geduldig und nachdenklich, wie schlimm es sein wird, wenn er die Datenbank einfach auf seine eigene Weise vom bedingten SQL-Entwickler aus bearbeitet.
3. Wenn der Änderungssatz bereits in das Repository übertragen wurde, vermeiden Sie eine Bearbeitung
Wenn ein anderer Entwickler einen Änderungssatz gezogen und angewendet hat, der später bearbeitet wird, wird er sich auf jeden Fall mit einem freundlichen Wort an Sie erinnern, wenn er beim Start der Anwendung eine Fehlermeldung erhält. Wenn die Bearbeitung des Änderungssatzes irgendwie in die Entwicklung eindringt, müssen Sie den steilen Weg der Hotfixes beschreiten. Der Kern des Problems liegt in der Validierung von Änderungen durch Hash-Summe – dem Hauptmechanismus von Liquibase. Beim Bearbeiten des Changeset-Codes ändert sich die Hash-Summe. Das Bearbeiten von Änderungssätzen ist nur möglich, wenn die gesamte Datenbank ohne Datenverlust von Grund auf bereitgestellt werden kann. In diesem Fall kann die Umgestaltung von SQL- oder XML-Code im Gegenteil das Leben einfacher machen und Migrationen lesbarer machen. Ein Beispiel wäre eine Situation, in der zu Beginn der Anwendung das Schema der Quelldatenbank im Team abgestimmt wurde.
4. Lassen Sie nach Möglichkeit Datenbanksicherungen überprüfen
Hier ist, denke ich, alles klar. Wenn die Migration plötzlich nicht erfolgreich war, kann alles zurückgegeben werden. Liquibase verfügt über ein Rollback-Tool, aber die Rollback-Skripte werden auch vom Entwickler selbst geschrieben und es kann mit der gleichen Wahrscheinlichkeit zu Problemen kommen wie bei den Haupt-Changeset-Skripten. Daher ist es in jedem Fall sinnvoll, mit Backups auf Nummer sicher zu gehen.
5. Verwenden Sie in der Entwicklung nach Möglichkeit verifizierte Datenbanksicherungen
Wenn dies nicht im Widerspruch zu Verträgen und Datenschutz steht, keine persönlichen Daten in der Datenbank vorhanden sind und es nicht wie zwei Sonnen wiegt – bevor Sie es auf Live-Migrationsserver anwenden, können Sie überprüfen, wie es auf dem Computer des Entwicklers funktioniert, und fast 100 % berechnen potenzieller Probleme bei der Migration.
6. Chatten Sie mit anderen Entwicklern im Team
In einem gut organisierten Entwicklungsprozess weiß jeder im Team, wer was macht. In der Realität ist dies jedoch häufig nicht der Fall. Wenn Sie im Rahmen Ihrer Aufgabe Änderungen in der Datenbankstruktur vorbereiten, empfiehlt es sich daher, zusätzlich das gesamte Team darüber zu informieren. Wenn jemand parallel Änderungen vornimmt, sollten Sie sich sorgfältig organisieren. Es lohnt sich, auch am Ende der Arbeit mit den Kollegen zu kommunizieren, nicht nur am Anfang. Viele potenzielle Probleme mit Änderungssätzen können in der Codeüberprüfungsphase gelöst werden.
7. Denken Sie darüber nach, was Sie tun!
Scheinbar selbstverständlicher Rat, der auf jede Situation anwendbar ist. Viele Probleme hätten jedoch vermieden werden können, wenn der Entwickler noch einmal analysiert hätte, was er tat und welche Auswirkungen es haben könnte. Die Arbeit mit Migrationen erfordert immer besondere Aufmerksamkeit und Genauigkeit.
Fallen
Schauen wir uns nun die typischen Fallen an, in die Sie tappen können, wenn Sie die oben genannten Ratschläge nicht befolgen, und was sollte eigentlich getan werden?
Situation 1: Zwei Entwickler versuchen gleichzeitig neue Änderungssätze hinzuzufügen

Vasya und Petya möchten einen Änderungssatz der Version 4 erstellen, ohne voneinander zu wissen. Sie nahmen Änderungen an der Datenbankstruktur vor und führten einen Pull-Request mit unterschiedlichen Changeset-Dateien aus. Im Folgenden wird der folgende Mechanismus vorgeschlagen:
Wie man sich entscheidet
- Irgendwie müssen sich die Kollegen auf die Reihenfolge einigen, in der ihre Änderungssätze erfolgen sollen, sagen wir, Petin soll zuerst angewendet werden.
- Eine Person sollte die andere einfüllen und Vasyas Changeset mit Version 5 markieren. Dies kann über Cherry Pick oder eine ordentliche Zusammenführung erfolgen.
- Überprüfen Sie nach den Änderungen unbedingt die Gültigkeit der durchgeführten Maßnahmen.
Tatsächlich ermöglichen Ihnen die Liquibase-Mechanismen, zwei Änderungssätze der Version 4 im Repository zu haben, sodass Sie alles so lassen können, wie es ist. Das heißt, Sie haben einfach zwei Revisionen von Version 4 mit unterschiedlichen Namen. Mit diesem Ansatz wird es später sehr schwierig, in Datenbankversionen zu navigieren.
Darüber hinaus birgt Liquibase, wie die Häuser der Hobbits, viele Geheimnisse. Einer davon ist der validCheckSum-Schlüssel, der seit Version 1.7 erscheint und es Ihnen ermöglicht, einen gültigen Hash-Wert für einen bestimmten Changeset anzugeben, unabhängig davon, was in der Datenbank gespeichert ist. Dokumentation sagt folgendes:
Fügen Sie eine Prüfsumme hinzu, die für dieses ChangeSet als gültig gilt, unabhängig davon, was in der Datenbank gespeichert ist. Wird hauptsächlich verwendet, wenn Sie ein ChangeSet ändern müssen und nicht möchten, dass Fehler in Datenbanken ausgelöst werden, in denen es bereits ausgeführt wurde (keine empfohlene Vorgehensweise).
Ja, das wird nicht empfohlen. Aber manchmal beherrscht ein starker Lichtmagier auch dunkle Techniken.
Fall 2: Datengesteuerte Migration

Nehmen wir an, Sie können keine Datenbanksicherungen von Live-Servern verwenden. Petya erstellte einen Änderungssatz, testete ihn lokal und stellte mit voller Gewissheit, dass er Recht hatte, eine Pull-Anfrage an den Entwickler. Für alle Fälle hat der Projektleiter geklärt, ob Petya es überprüft hat, und es dann eingefüllt. Aber die Bereitstellung auf dem Entwicklungsserver ist zurückgegangen.
Tatsächlich ist dies möglich und niemand ist davor gefeit. Dies geschieht, wenn die Änderungen der Tabellenstruktur irgendwie mit bestimmten Daten aus der Datenbank verknüpft sind. Wenn Petyas Datenbank nur mit Testdaten gefüllt ist, deckt sie natürlich nicht alle Problemfälle ab. Wenn Sie beispielsweise eine Tabelle löschen, stellt sich heraus, dass es Datensätze in anderen Tabellen gibt, deren Fremdschlüssel mit Datensätzen in der zu löschenden Tabelle verknüpft ist. Oder es stellt sich bei einer Änderung des Spaltentyps heraus, dass nicht 100 % der Daten in den neuen Typ konvertiert werden können.
Wie man sich entscheidet
- Schreiben Sie spezielle Skripte, die einmalig bei der Migration angewendet werden und bringen Sie die Daten in die richtige Form. Dies ist eine allgemeine Methode zur Lösung des Problems der Übertragung von Daten in neue Strukturen nach der Anwendung von Migrationen. In besonderen Fällen kann jedoch auch vorher etwas Ähnliches angewendet werden. Dieser Weg ist natürlich nicht immer verfügbar, da die Bearbeitung von Daten auf Live-Servern gefährlich und sogar tödlich sein kann.
- Eine weitere knifflige Möglichkeit besteht darin, einen vorhandenen Änderungssatz zu bearbeiten. Die Schwierigkeit besteht darin, dass alle Datenbanken, in denen es bereits in seiner bestehenden Form angewendet wurde, wiederhergestellt werden müssen. Es ist durchaus möglich, dass das gesamte Backend-Team gezwungen ist, die Datenbank lokal von Grund auf neu aufzurollen.
- Und der universellste Weg besteht darin, das Datenproblem in die Entwicklerumgebung zu übertragen, die gleiche Situation neu zu erstellen und einem defekten Änderungssatz einen neuen Änderungssatz hinzuzufügen, der das Problem umgeht.

Generell gilt: Je ähnlicher die Datenbank in ihrer Zusammensetzung der Datenbank des Produktionsservers ist, desto geringer ist die Wahrscheinlichkeit, dass Probleme bei Migrationen weitreichende Ausmaße annehmen. Und bevor Sie den Änderungssatz an das Repository senden, sollten Sie natürlich mehrmals darüber nachdenken, ob dadurch etwas kaputt geht.
Situation 3: Die Nutzung von Liquibase beginnt, nachdem es in Produktion gegangen ist
Angenommen, der Teamleiter hat Petya gebeten, Liquibase in das Projekt einzubinden, aber das Projekt befindet sich bereits in der Produktion und es gibt bereits eine vorhandene Datenbankstruktur.
Dementsprechend besteht das Problem darin, dass auf allen neuen Servern oder Entwicklermaschinen die Tabellendaten von Grund auf neu erstellt werden müssen und die bereits vorhandene Umgebung in einem konsistenten Zustand bleiben und bereit sein muss, neue Änderungssätze zu akzeptieren.
Wie man sich entscheidet
Es gibt auch mehrere Möglichkeiten:
- Die erste und naheliegendste besteht darin, ein separates Skript zu haben, das beim Initialisieren einer neuen Umgebung manuell angewendet werden muss.
- Die zweite, weniger offensichtliche Möglichkeit besteht darin, eine Liquibase-Migration in einem anderen Liquibase-Kontext durchzuführen und diese anzuwenden. Mehr über Liquibase Context können Sie hier lesen: . Generell handelt es sich hierbei um einen interessanten Mechanismus, der beispielsweise zum Testen erfolgreich eingesetzt werden kann.
- Der dritte Weg besteht aus mehreren Schritten. Zunächst muss eine Migration für bestehende Tabellen erstellt werden. Dann muss es auf eine Umgebung angewendet werden und so wird seine Hash-Summe ermittelt. Der nächste Schritt besteht darin, leere Liquibase-Tabellen auf unserem nicht leeren Server zu initialisieren, und Sie können manuell einen Datensatz eines „als ob angewendet“-Änderungssatzes mit den bereits in der Datenbank vorhandenen Änderungen in die Tabelle mit dem Verlauf der angewendeten Änderungssätze einfügen. Somit beginnt der Verlauf auf einem bereits vorhandenen Server mit Version 2 und alle neuen Umgebungen verhalten sich identisch.

Szenario 4: Die Migrationen werden riesig und können nicht mithalten
Zu Beginn der Serviceentwicklung wird Liquibase in der Regel als externe Abhängigkeit verwendet und alle Migrationen werden beim Start der Anwendung verarbeitet. Im Laufe der Zeit kann es jedoch passieren, dass Sie auf folgende Fälle stoßen:
- Migrationen werden riesig und dauern lange.
- Es besteht die Notwendigkeit, in verteilten Umgebungen beispielsweise auf mehreren Instanzen von Datenbankservern gleichzeitig zu migrieren.
In diesem Fall führt die zu lange Anwendung von Migrationen zu einer Zeitüberschreitung beim Start der Anwendung. Außerdem kann die Anwendung von Migrationen pro Anwendungsinstanz dazu führen, dass sich verschiedene Server in einem nicht synchronen Zustand befinden.
Wie man sich entscheidet
In solchen Fällen ist Ihr Projekt bereits groß, vielleicht sogar schon erwachsen, und Liquibase beginnt als separates externes Tool zu fungieren. Tatsache ist, dass Liquibase als Bibliothek in einer JAR-Datei zusammengestellt wird und sowohl als Abhängigkeit innerhalb des Projekts als auch eigenständig funktionieren kann.
Offline können Sie die Durchführung von Migrationen Ihrer CI/CD-Umgebung oder den starken Schultern Ihrer Systemadministratoren/Bereitsteller überlassen. Dazu benötigen Sie die Liquibase-Befehlszeile . In diesem Modus ist es möglich, die Anwendung zu starten, nachdem alle erforderlichen Migrationen abgeschlossen sind.
Abschluss
Tatsächlich gibt es bei der Arbeit mit Datenbankmigrationen noch viel mehr Fallstricke, und viele davon erfordern einen kreativen Ansatz. Es ist wichtig zu verstehen, dass die meisten dieser Fallen vermieden werden können, wenn Sie das Werkzeug richtig verwenden. Konkret musste ich mich mit allen aufgeführten Problemen in unterschiedlicher Form auseinandersetzen, und einige davon waren das Ergebnis meiner Fehler. Im Grunde geschieht dies natürlich aus Unaufmerksamkeit, manchmal aber auch aufgrund der kriminellen Unfähigkeit, das Tool zu nutzen.
Source: habr.com


