Datenbankupdate in Production Spring Boot

Hallo zusammen, langsam werd ich mit Spring und Hibernate warm. Eine wichtige Frage habe ich aber noch. Ich habe eine tenante Datenbank, heißt jeder User hat sein eigenes Schema. Wenn ich nun am Programm etwas erweitere, müsste ich ja die Datenbanken updaten. Über den Updatemechanismus von Spring soll man das nicht machen, da es nur für Dev gedacht ist.

Außerdem muss eine neue Datenbank eingerichtet werden, wenn es einen neuen Kunden gibt. Ich würde nun ein Script erstellen create.sql das immer auf dem neuesten Stand ist und auf der neuen Kundendatenbank ausgeführt wird. Wie aber mit Updates? Die User sollten alle auf dem aktuellen Stand sein, ich würde es spontan so machen: User logged sich ein, es wird geprüft ob die Datenbank noch up to Date ist (nur wie?) und wenn nötig ein Update drüber ziehen.

Hm so und nun bitte ich um euer Feedback, hat jemand Erfahrungen mit sowas?

Ich kenne mich mit tenant DBs nicht aus und weiß auch nicht, welcher Weg über Spring nur für Devs sein soll. Allerdings nutze ich für Datenbankmigrationen gerne Flyway. Das hilft Dir vielleicht.

Was meinst du mit dem Updatemechanismus von Spring?

Generell klingt das danach, als ob Flyway oder Liquibase das passende wären, sowohl für das Update als auch das Anlegen. Kann man beides automatisch oder manuell mit Spring oder unabhängig davon laufen lassen.

Mit Updatemechanismus von Spring mein ich das hier: spring.jpa.hibernate.ddl-auto = update

Das ist nichts für production code. Hibernate passt dir einfach das Schema an und du kannst nicht sagen, was tatsächlich passiert. Selbst wenn Version x → y getestet ist und sicher funktioniert, dann kannst du das nicht für Version x → z behaupten.

Wie bereits erwähnt: nutze Liquibase oder Flyway zum aufsetzen deiner Datenbank. Ich kenne jetzt nur liquibase, tippe aber mal bei Flyway ist es ähnlich: Du hast einzelne migrationsscripte und die rennen nacheinander. Die kannst du dann auch nutzen um eine neue Datenbank aufzusetzen. Und du weißt eben wirklich mit Sicherheit, was mit jedem Schritt passiert.

Ok dann muss ich mir das wohl mal ansehen danke. Gibt es eine einfache Möglichkeit aus meinen @Entity irgendwie SQL Script zu bekommen oder macht das Flyway respektive Liquibase?

Welches der beiden ist most recommended? Flyway hab ich was mit 2500$ gesehen oO wenn man nicht die Community Edition nutzen möchte

Edit: das große Problem wird meine tenantz sein, das wird mit den beiden Frameworks evtl. nicht Laufen?

Ich wusste überhaupt nicht, dass es eine Bezahlversion gibt. Nie benötigt.
Es gibt verschiedene Tools, um aus einer bestehenden DB SQL für die Erzeugung zu erstellen. SQL Developer sollte dies als Beispiel können.

Ja das hab ich auch erst überlegt. Ich lasse auf meinem Testserver, die Datenbanken von Spring erstellen und exportiere mir dann daraus SQL scripts. Ist vielleichte erstmal Aufwand aber ich kann nachvollziehen was gemacht wird. Wenn ich das Script dann für gut befinde, müsste es auf den Userdatenbanken ausgeführt werden, gibt es in Hibernate irgendwas womit ich CREATE TABLE etc ausführen kann oder sogar ein SQL File übergeben?

Du kannst wirklich Flyway nehmen.

Dazu musst du lediglich die Namen deiner SQL-Skripte mit einer Version versehen und Flyway als Dependency hinzufügen. Der Rest funktioniert dann automatisch. Es werden nur die Skripte ausgeführt, die noch nicht ausgeführt wurden, entsprechend der Versionsnummer.

Ansonsten müsste man die Statements aus der Datei parsen und einzeln ausführen.

Mit Liquibase dürfte das genauso gehen, da gibts Maven-Plugins, die dir direkt aus den Entitys die passenden Change-Sets generieren, ohne das man irgendwas selbst mit SQL machen muss.

Das Video ist gut danke, dort muss ich aber scripte hinterlegen. Meine relationen sind relativ komplex, was das Erstellen der .sql aufwändig macht. Könnte mir von Hibernate die queries ausgeben lassen aber vielleicht gibts ja noch ne einfachere Lösung aus den entity Klassen, Queries zu erstellen? Muss das mal testen ob das mit meinem tenanten System auch funktioniert, wenn nicht hm Plan B

Wir benutzen liquibase und sind damit sehr zufrieden.

Bevor man anfängt liquibase oder flyway Script zu schreiben, muss man sich über die Struktur Gedanken machen.

Naiv drauf los und von JPA scripte automatisch anlegen lassen wird schnell unübersichtlich.

Da muss man sich best practices vorher ansehen.

In einem mandantenfähigen Projekt nutze ich auch flyway für die Schemaerstellung.
Ganz transparent geht das aufgrund der tenancy aber nicht. An entsprechender Stelle im Code wird die Migration dann für den jeweiligen Mandanten mit dem Java-API getriggert.

Ah okay! Ich habe eine Klasse in welcher alle Mandanten (gutes Wort, besser als Tenant :slight_smile:) in werlcher eine Map mit Datasources erstellt wird, hier würde ich das einbauen. Oder aber man baut es in einen Controller ein? Zb speichere ich einen Wert in der Mandanten-Datenbank der vor jedem Login und vor jeder Action erstmal überprüft wird (eine Art Token). In diesem Controller könnte ich Flyway einbauen, dass es die Datenbankversion checked und ggf updated? Wäre das schon das von dir angesprochene „triggern“?

Flyway flyway = new Flyway();
flyway.setDataSource(url, user, password);
flyway.migrate();

Das macht schon deswegen keinen Sinn, weil die Datenbank sich wohl kaum ändern wird im laufenden Betrieb. Es müsste also bem Startup oder nach einem hotdeploy (falls erlaubt) durchgeführt werden.

Außerdem müssen alle Mandanten zu dem passenden Softwarestand das passende Schema haben. Alle Mandanten ungeachtet der Software updaten wäre wohl nicht korrekt.

1 „Gefällt mir“

Ah ja stimmt das macht Sinn, dann wäre es wohl in der main Methode am besten aufgehoben. (Bei Startup)

Passend wäre vermutlich ein ApplicationListener, der auf ContextRefreshedEvents lauscht

Ich habe das beim Startup und im Codeabschnitt zum Anlegen eines neuen Mandanten getriggert.
Aber nicht in der Mainmethode, sondern mittels Initialisierungshooks.

1 „Gefällt mir“

Dankeee für den Tipp, klappt super :slight_smile: Wieder ein Problem weniger.

Hierzu noch eine Frage, ich habe grad folgendes Szenario:

Ich habe ein V1__create.sql da werden alle Tables erstellt.

Nun hab ich mich entschieden, auto_increment zu nutzen, statt von Hibernate die ID genieren zu lassen. Heißt ich müsste jetzt V2__add_increment.sql erstellen und alle Tables altern.

Wenn ich dann eine neue Datenbank erstelle, macht er erst V1, dann V2 um die Tabelle zu updaten oder? Könnte ich nicht die V2 in die V1 integrieren damit er beim Erstellen einer neuen DB nur 1 Datei ausführen muss? Aber dann stimmen die Versionen nicht, also MUSS V2 ausgeführt werden oder?

Wenn ich viele Änderungen und Anpassungen habe und im Laufe der Zeit vielleicht neue Tabellen, und so weiter hinzu kommen, können das ja schon ein wenig mehr Script werden. Dann dauert das Erstellen einer DB uU lange. Danke für Input hierzu :slight_smile: