- PVSM.RU - https://www.pvsm.ru -
Liquibase представляет из себя систему управления версиями базы данных, в основном это касается структуры и в меньшей степени содержимого базы. При этом описание базы с одной стороны достаточно абстрактно и позволяет использовать на нижнем уровне различные СУБД, и с другой стороны всегда можно перейти на SQL-диалект конкретной СУБД, что достаточно гибко. Liquibase является устоявшимся проектом с открытым исходным кодом и активно используется за пределами своей родной Java среды и не требует глубоких знаний Java для работы. В качестве описания структуры базы и изменений базы исторически использовался XML формат, однако сейчас параллельно поддерживается YAML и JSON.
В данной статье мы немного обобщим опыт предыдущих поколений и сосредоточимся на работе с Liquibase с использованием Maven. В качестве тестовой операционной системы будем использовать Ubuntu.
Запускать Liquibase можно несколькими способами, однако наиболее удобно использовать Maven — по сути Java Make.
sudo apt install maven
mvn -version
В качестве Makefile здесь выступает 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>
После того как мы сделали pom.xml можно запускать обновление базы — команда liquibase:update.
Для этого нам потребуются:
liquibase.properties
username=test
password=test
referenceUsername=test
#можно задавать и другие параметры
#url=jdbc:postgresql://dev/test
#referenceUrl=jdbc:postgresql://dev/test_reference
Основным понятием liquibase являются так называемые изменения базы (changesets). Они могут включать в себя как изменения структуры так и изменение данных. Для контроля примененных изменений liquibase использует таблицы databasechangelog и databasechangeloglock.
<?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>
Здесь выполняется liquibase:update для профиля dev и базы из liquibase.url, которая указана в стандартном JDBC формате. После обновления в базе появляется указанная в changeSet таблица и две служебные таблицы databasechangelog и databasechangeloglock.
#!/usr/bin/env bash
mvn liquibase:update
-Denv=dev
-Dliquibase.url="jdbc:postgresql://dev/test?prepareThreshold=0&stringtype=unspecified"
Иногда перед запуском изменений требуется посмотреть содержимое создаваемых запросов. Для этого предназначены команды liquibase:updateSQL и liquibase:rollbackSQL.
#!/usr/bin/env bash
mvn liquibase:updateSQL
-Denv=dev
-Dliquibase.url="jdbc:postgresql://dev/test?prepareThreshold=0&stringtype=unspecified" > /tmp/script.sql
Изменения могут быть в разных форматах, в том числе обычный sql или он же в отдельном файле.
Каждое изменение может включать секцие rollback позволяющую откатывать изменения командой liqubase:rollback. Кроме того для маркировки изменений, например для более удобного отката туда, можно использовать tagDatabase.
<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>
<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>
<changeSet context="legacy" author="author" id="1-user">
<sqlFile dbms="postgresql" path="sql/some.sql" relativeToChangelogFile="true" />
<rollback> delete from "some"; </rollback>
</changeSet>
<changeSet context="legacy" author="author" id="1-initial-changeset">
<tagDatabase tag="initial"/>
</changeSet>
Для более удобного управления различными конфигурациями, например development/production можно использовать контексты. Контекст указывается в changeSet аттрибуте context и затем запускается Maven параметром -Dcontexts.
<changeSet context="legacy" author="author" id="1-initial-changeset">
<tagDatabase tag="initial"/>
</changeSet>
#!/usr/bin/env bash
mvn liquibase:update
-Denv=dev
-Dliquibase.url="jdbc:postgresql://dev/test?prepareThreshold=0&stringtype=unspecified"
-Dliquibase.contexts=non-legacy
Операция обратная обновлению, в большинстве случаев поддерживается автоматически. Для прочих возможно задание через секцию rollback. Запускается командой liquibase:rollback.
<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>
#!/usr/bin/env bash
mvn liquibase:update
-Denv=dev
-Dliquibase.url="jdbc:postgresql://dev/test?prepareThreshold=0&stringtype=unspecified"
-Dliquibase.contexts=non-legacy
В разработке удобно использовать для сравнения двух существующих баз на предмет внесённых изменений. В настройки (или параметры запуска) потребуется добавить ссылку на референсную базу и данные для доступа к ней.
liquibase.properties
referenceUsername=test
referenceUrl=jdbc:postgresql://dev/test_reference
Сравнение схем url и referenceUrl.
#!/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
Также бывает полезно сохранить текущую схему базы, с данными или без.
Сохранение схемы существующей базы.
#!/usr/bin/env bash
mvn liquibase:generateChangeLog
-Denv=dev
-Dliquibase.url="jdbc:postgresql://dev/test_reference?prepareThreshold=0"
-Dliquibase.outputChangeLogFile=dev/changelog.xml
Сохранение схемы существующей базы с данными.
#!/usr/bin/env bash
mvn liquibase:generateChangeLog
-Denv=dev
-Dliquibase.url="jdbc:postgresql://dev/test_reference?prepareThreshold=0"
-Dliquibase.outputChangeLogFile=dev/changelog.xml
Существуют отпределенные проблемы с выгрузкой, сравнением и применением бинарных данных, в частности проблема с генерацией изменений.
Наряду с Liquibase пользуется популярностью в Java сообществе — http://flywaydb.org/documentation [8]
Аналог на Perl — http://sqitch.org [9]
Аналог для .Net — https://github.com/schambers/fluentmigrator [10]
Аналог для Ruby — http://dbgeni.appsintheopen.com/manual.html [11]
pom.xml - maven makefile
dev
liquibase.properties - login/password etc
master.xml - changesets
<createTable tableName="t_name">
...
<column name="doubleArray" type="DOUBLE_ARRAY"/>
...
</createTable>
<modifySql dbms="postgresql">
<replace replace="DOUBLE_ARRAY" with="double precision[][]"/>
</modifySql>
Автор: ki77roy
Источник [25]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/java/306029
Ссылки в тексте:
[1] https://habr.com/en/post/179425/: https://habr.com/en/post/179425/
[2] https://habr.com/en/post/178665/: https://habr.com/en/post/178665/
[3] https://habr.com/en/post/333762/: https://habr.com/en/post/333762/
[4] https://habr.com/en/post/251617/: https://habr.com/en/post/251617/
[5] https://liquibase.jira.com/browse/CORE-2650: https://liquibase.jira.com/browse/CORE-2650
[6] https://liquibase.jira.com/browse/CORE-2906: https://liquibase.jira.com/browse/CORE-2906
[7] https://github.com/liquibase/liquibase: https://github.com/liquibase/liquibase
[8] http://flywaydb.org/documentation: http://flywaydb.org/documentation
[9] http://sqitch.org: http://sqitch.org
[10] https://github.com/schambers/fluentmigrator: https://github.com/schambers/fluentmigrator
[11] http://dbgeni.appsintheopen.com/manual.html: http://dbgeni.appsintheopen.com/manual.html
[12] https://www.liquibase.org/documentation/existing_project.html: https://www.liquibase.org/documentation/existing_project.html
[13] https://www.liquibase.org/documentation/contexts.html: https://www.liquibase.org/documentation/contexts.html
[14] https://www.liquibase.org/documentation/changeset.html: https://www.liquibase.org/documentation/changeset.html
[15] https://www.liquibase.org/documentation/databasechangelog_table.html: https://www.liquibase.org/documentation/databasechangelog_table.html
[16] http://www.liquibase.org/documentation/json_format.html: http://www.liquibase.org/documentation/json_format.html
[17] https://www.liquibase.org/documentation/changes/sql.html: https://www.liquibase.org/documentation/changes/sql.html
[18] https://www.liquibase.org/documentation/changes/sql_file.html: https://www.liquibase.org/documentation/changes/sql_file.html
[19] https://www.liquibase.org/documentation/column.html: https://www.liquibase.org/documentation/column.html
[20] https://www.liquibase.org/documentation/maven/generated/update-mojo.html: https://www.liquibase.org/documentation/maven/generated/update-mojo.html
[21] https://www.liquibase.org/documentation/maven/generated/generateChangeLog-mojo.html: https://www.liquibase.org/documentation/maven/generated/generateChangeLog-mojo.html
[22] http://www.liquibase.org/documentation/modify_sql.html: http://www.liquibase.org/documentation/modify_sql.html
[23] https://stackoverflow.com/questions/28240068/create-column-of-type-double-precision-with-liquibase: https://stackoverflow.com/questions/28240068/create-column-of-type-double-precision-with-liquibase
[24] https://news.ycombinator.com/item?id=10145933: https://news.ycombinator.com/item?id=10145933
[25] Источник: https://habr.com/ru/post/436994/?utm_campaign=436994
Нажмите здесь для печати.