Einführung
Liquibase ist ein Datenbankversionskontrollsystem, das hauptsächlich die Struktur und in geringerem Maße den Inhalt der Datenbank betrifft. Gleichzeitig ist die Beschreibung der Datenbank einerseits recht abstrakt und ermöglicht die Verwendung verschiedener DBMS auf der unteren Ebene, andererseits können Sie jederzeit zum SQL-Dialekt eines bestimmten DBMS wechseln, der sehr flexibel ist. Liquibase ist ein etabliertes Open Source-Projekt und wird außerhalb seiner nativen Java-Umgebung aktiv verwendet. Für die Arbeit sind keine umfassenden Java-Kenntnisse erforderlich. In der Vergangenheit wurde ein XML-Format verwendet, um die Basisstruktur und Basisänderungen zu beschreiben. Jetzt werden YAML und JSON parallel unterstützt.
In diesem Artikel werden wir die Erfahrungen früherer Generationen kurz zusammenfassen und uns auf die Arbeit mit Liquibase mit Maven konzentrieren. Wir werden Ubuntu als Testbetriebssystem verwenden.
Andere Artikel über Liquibase
Umgebungseinstellung
Es gibt verschiedene Möglichkeiten, Liquibase zu starten. Am bequemsten ist es jedoch, Maven oder Gradle zu verwenden.
sudo apt install maven mvn -version
Hier fungiert pom.xml als Makefile - es enthält bereits alle notwendigen Abhängigkeiten, Einstellungen und Profile.
pom.xml <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.test.db</groupId> <artifactId>db</artifactId> <version>1.0.0</version> <name>db</name> <description>Test Database</description> <packaging>pom</packaging> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <slf4j.version>1.7.24</slf4j.version> <logback.version>1.2.3</logback.version> <liquibase.version>3.6.2</liquibase.version> <postgresql.version>42.2.5</postgresql.version> <snakeyaml.version>1.23</snakeyaml.version> </properties> <dependencies> <!--Logging--> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>${slf4j.version}</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>log4j-over-slf4j</artifactId> <version>${slf4j.version}</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>jcl-over-slf4j</artifactId> <version>${slf4j.version}</version> </dependency> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> <version>${logback.version}</version> </dependency> <!--JDBC drivers--> <dependency> <groupId>org.postgresql</groupId> <artifactId>postgresql</artifactId> <version>${postgresql.version}</version> </dependency> <dependency> <groupId>org.liquibase</groupId> <artifactId>liquibase-core</artifactId> <version>${liquibase.version}</version> </dependency> <dependency> <groupId>org.yaml</groupId> <artifactId>snakeyaml</artifactId> <version>${snakeyaml.version}</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.liquibase</groupId> <artifactId>liquibase-maven-plugin</artifactId> <version>${liquibase.version}</version> <configuration> <propertyFile>${profile.propertyFile}</propertyFile> <changeLogFile>${profile.changeLogFile}</changeLogFile> <dataDir>${profile.dataDir}</dataDir> <!-- log --> <verbose>${profile.verbose}</verbose> <logging>${profile.logging}</logging> <promptOnNonLocalDatabase>false</promptOnNonLocalDatabase> </configuration> </plugin> </plugins> </build> <profiles> <!-- Development settings, -Denv=dev --> <profile> <id>dev</id> <activation> <property> <name>env</name> <value>dev</value> </property> </activation> <properties> <profile.propertyFile>dev/liquibase.properties</profile.propertyFile> <profile.changeLogFile>dev/master.xml</profile.changeLogFile> <profile.dataDir>dev/data</profile.dataDir> <profile.verbose>true</profile.verbose> <profile.logging>debug</profile.logging> </properties> </profile> <!-- Production settings, -Denv=prod --> <profile> <id>prod</id> <activation> <property> <name>env</name> <value>prod</value> </property> </activation> <properties> <profile.propertyFile>prod/liquibase.properties</profile.propertyFile> <profile.changeLogFile>prod/master.xml</profile.changeLogFile> <profile.dataDir>prod/data</profile.dataDir> <profile.verbose>false</profile.verbose> <profile.logging>info</profile.logging> </properties> </profile> </profiles> </project>
Wir starten das Update
Nachdem wir pom.xml erstellt haben, können wir mit der Aktualisierung der Datenbank beginnen - dem Befehl liquibase: update.
Dafür brauchen wir:
- Datei liquibase.properties mit Einstellungen für die Verbindung zur Datenbank (Benutzername / Passwort und möglicherweise andere Parameter)
- XML-Datei mit Basisänderungen
- sh Datenbank-Update-Startskript
Datei mit den Einstellungen für die Datenbankverbindung
liquibase.properties
username=test password=test referenceUsername=test # #url=jdbc:postgresql://dev/test #referenceUrl=jdbc:postgresql://dev/test_reference
Basisänderungsdatei
Das Hauptkonzept der Liquibase sind die sogenannten Basenänderungen (Changesets). Sie können sowohl strukturelle Änderungen als auch Datenänderungen umfassen. Liquibase verwendet die Tabellen databasechangelog und databasechangeloglock , um die angewendeten Änderungen zu überwachen.
<?xml version="1.1" encoding="UTF-8" standalone="no"?> <databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog" xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog-ext http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.6.xsd"> <changeSet context="legacy" author="author (generated)" id="1"> <createTable tableName="test"> <column autoIncrement="true" name="id" type="SERIAL"> <constraints nullable="false"/> </column> <column name="user_name" type="VARCHAR(255)"/> <column name="preferences" type="TEXT"/> </createTable> </changeSet> </databaseChangeLog>
Startskript für die Datenbankaktualisierung
Hier wird liquibase: update für das Entwicklungsprofil und die Basis von liquibase.url ausgeführt, die im Standard-JDBC-Format angegeben ist. Nach der Aktualisierung werden die in changeSet angegebene Tabelle und zwei Servicetabellen databasechangelog und databasechangeloglock in der Datenbank angezeigt.
#!/usr/bin/env bash mvn liquibase:update\ -Denv=dev\ -Dliquibase.url="jdbc:postgresql://dev/test?prepareThreshold=0&stringtype=unspecified"
SQL-Generierung ohne Aktualisierung der Datenbank
Manchmal müssen Sie vor dem Starten von Änderungen den Inhalt der generierten Anforderungen überprüfen. Zu diesem Zweck sind die Befehle liquibase: updateSQL und liquibase: rollbackSQL vorgesehen.
#!/usr/bin/env bash mvn liquibase:updateSQL\ -Denv=dev\ -Dliquibase.url="jdbc:postgresql://dev/test?prepareThreshold=0&stringtype=unspecified" > /tmp/script.sql
Mehr zu changeSet
Änderungen können in verschiedenen Formaten erfolgen, einschließlich regulärem SQL oder in einer separaten Datei.
Jede Änderung kann einen Rollback-Abschnitt enthalten, mit dem Sie die Änderungen mit dem Befehl liquibase: rollback zurücksetzen können . Darüber hinaus können Sie tagDatabase verwenden , um Änderungen zu markieren, z. B. um dort bequemer zurückzusetzen.
<changeSet context="legacy" author="author (generated)" id="1"> <createTable tableName="test"> <column autoIncrement="true" name="id" type="SERIAL"> <constraints primaryKey="true" primaryKeyName="test_pkey"/> </column> <column name="c1" type="VARCHAR(255)"/> <column name="c2" type="INTEGER"/> <column name="c3" type="SMALLINT"/> <column name="c4" type="VARCHAR(255)"/> <column name="c5" type="TEXT"/> <column name="c6" type="VARCHAR(255)"/> </createTable> </changeSet>
Embedded SQL
<changeSet context="legacy" author="author" id="1-domain-some-domain"> <sql> CREATE DOMAIN public.some_domain AS bigint; ALTER DOMAIN public.some_domain OWNER TO test; </sql> <rollback> DROP DOMAIN public.some_domain; </rollback> </changeSet>
SQL-Datei
<changeSet context="legacy" author="author" id="1-user"> <sqlFile dbms="postgresql" path="sql/some.sql" relativeToChangelogFile="true" /> <rollback> delete from "some"; </rollback> </changeSet>
Tags
<changeSet context="legacy" author="author" id="1-initial-changeset"> <tagDatabase tag="initial"/> </changeSet>
Kontexte starten
Für eine bequemere Verwaltung verschiedener Konfigurationen, z. B. Entwicklung / Produktion, können Kontexte verwendet werden. Der Kontext wird im changeSet- Attribut des Kontexts angegeben und dann von Maven mit dem Parameter -Dcontexts gestartet.
Mit dem Kontext ändern
<changeSet context="legacy" author="author" id="1-initial-changeset"> <tagDatabase tag="initial"/> </changeSet>
Auslösen von Kontextänderungen
#!/usr/bin/env bash mvn liquibase:update\ -Denv=dev\ -Dliquibase.url="jdbc:postgresql://dev/test?prepareThreshold=0&stringtype=unspecified"\ -Dliquibase.contexts=non-legacy
Änderungen rückgängig machen
Der Vorgang ist das Gegenteil von Aktualisierung. In den meisten Fällen wird er automatisch unterstützt. Für andere ist die Aufgabe über den Rollback-Bereich möglich. Es wird mit dem Befehl liquibase: rollback gestartet.
Mit Rollback ändern
<changeSet context="legacy" author="author" id="1-domain-some-domain"> <sql> CREATE DOMAIN public.some_domain AS bigint; ALTER DOMAIN public.some_domain OWNER TO test; </sql> <rollback> DROP DOMAIN public.some_domain; </rollback> </changeSet>
Rollback starten
#!/usr/bin/env bash mvn liquibase:update\ -Denv=dev\ -Dliquibase.url="jdbc:postgresql://dev/test?prepareThreshold=0&stringtype=unspecified"\ -Dliquibase.contexts=non-legacy
Vergleich
In der Entwicklung ist es zweckmäßig, zwei vorhandene Datenbanken auf die vorgenommenen Änderungen zu vergleichen. In den Einstellungen (oder Startparametern) müssen Sie einen Link zur Referenzdatenbank und zu den Daten für den Zugriff hinzufügen.
liquibase.properties
referenceUsername=test referenceUrl=jdbc:postgresql://dev/test_reference
Schaltungsvergleich
Vergleichen von URL- und ReferenceUrl-Schemata.
#!/usr/bin/env bash mvn liquibase:diff\ -Denv=dev\ -Dliquibase.referenceUrl="jdbc:postgresql://dev/test?prepareThreshold=0"\ -Dliquibase.url="jdbc:postgresql://dev/test_reference?prepareThreshold=0"\ -Dliquibase.diffChangeLogFile=dev/diff.xml
Schema speichern
Es kann auch nützlich sein, das aktuelle Datenbankschema mit oder ohne Daten zu speichern. Es muss berücksichtigt werden, dass Liquibase ein Schema speichert, das nicht vollständig dem Original entspricht. Beispielsweise müssen die verwendeten Domänen oder die Vererbung separat hinzugefügt werden (siehe Einschränkungen).
Speichern eines Schemas ohne Berücksichtigung von Daten
Speichern des Schemas einer vorhandenen Datenbank.
#!/usr/bin/env bash mvn liquibase:generateChangeLog\ -Denv=dev\ -Dliquibase.url="jdbc:postgresql://dev/test_reference?prepareThreshold=0"\ -Dliquibase.outputChangeLogFile=dev/changelog.xml
Speichern eines Schemas mit Daten
Speichern des Schemas einer vorhandenen Datenbank mit Daten.
#!/usr/bin/env bash mvn liquibase:generateChangeLog\ -Denv=dev\ -Dliquibase.url="jdbc:postgresql://dev/test_reference?prepareThreshold=0"\ -Dliquibase.outputChangeLogFile=dev/changelog.xml
Einschränkungen und Probleme
Arbeiten mit Binärdaten in der Datenbank
Es gibt bestimmte Probleme beim Hochladen, Vergleichen und Verwenden von Binärdaten, insbesondere beim Generieren von Änderungen.
Vererbung und gemeinsame Spalten
Quellcode
Alternative Lösungen
Flyway
Zusammen mit Liquibase ist in der Java-Community beliebt - http://flywaydb.org/documentation
Sqqitch
Perl-Äquivalent - http://sqitch.org
Fluentmigrator
Analog für .Net - https://github.com/schambers/fluentmigrator
Dbgeni
Analog für Ruby - http://dbgeni.appsintheopen.com/manual.html
Anwendungen
Projektstruktur
pom.xml - maven makefile dev liquibase.properties - login/password etc master.xml - changesets
So fügen Sie einem vorhandenen Projekt Liquibase hinzu
Wie Basisänderungen funktionieren
Mehr zum Update
Mehr zur Änderungsgenerierung
Weitere Informationen zu benutzerdefiniertem SQL
Verarbeitung datenbankspezifischer Datentypen
<createTable tableName="t_name"> ... <column name="doubleArray" type="DOUBLE_ARRAY"/> ... </createTable> <modifySql dbms="postgresql"> <replace replace="DOUBLE_ARRAY" with="double precision[][]"/> </modifySql>
Andere