Liquibase e Maven

1. Introdução


O Liquibase é um sistema de controle de versão de banco de dados, que diz respeito principalmente à estrutura e, em menor grau, ao conteúdo do banco de dados. Além disso, a descrição do banco de dados é, por um lado, bastante abstrata e permite o uso de vários DBMSs no nível inferior e, por outro lado, você sempre pode alternar para o dialeto SQL de um DBMS específico, que é bastante flexível. O Liquibase é um projeto de código aberto estabelecido e é usado ativamente fora de seu ambiente Java nativo e não requer conhecimento aprofundado de Java para funcionar. Historicamente, um formato XML tem sido usado para descrever a estrutura e as alterações da base, mas agora o YAML e o JSON são suportados em paralelo.


Neste artigo, resumiremos brevemente a experiência das gerações anteriores e focaremos no trabalho com o Liquibase usando o Maven. Usaremos o Ubuntu como um sistema operacional de teste.


Outros artigos sobre Liquibase



Configuração do ambiente


Existem várias maneiras de iniciar o Liquibase; no entanto, Maven ou Gradle são mais convenientes.


sudo apt install maven mvn -version 

Aqui o pom.xml atua como um Makefile - ele já contém todas as dependências, configurações e perfis necessários.


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> 

Lançamos atualização


Depois de concluir o pom.xml, podemos começar a atualizar o banco de dados - o comando liquibase: update.


Para isso, precisamos:


  • arquivo liquibase.properties com configurações para conectar-se ao banco de dados (nome de usuário / senha e possivelmente outros parâmetros)
  • arquivo xml com alterações básicas
  • script de inicialização da atualização do banco de dados sh

Arquivo de configurações de conexão com o banco de dados


liquibase.properties


 username=test password=test referenceUsername=test #     #url=jdbc:postgresql://dev/test #referenceUrl=jdbc:postgresql://dev/test_reference 

Arquivo de alterações básicas


O principal conceito de liquibase são as chamadas alterações básicas (changesets). Eles podem incluir alterações estruturais e alterações de dados. O Liquibase usa as tabelas databasechangelog e databasechangeloglock para monitorar as alterações aplicadas.


 <?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> 

Script de inicialização da atualização do banco de dados


Aqui liquibase: update é executado para o perfil de desenvolvedor e a base de liquibase.url, que é especificado no formato JDBC padrão. Após a atualização, a tabela indicada em changeSet e duas tabelas de serviço databasechangelog e databasechangeloglock aparecem no banco de dados .


 #!/usr/bin/env bash mvn liquibase:update\ -Denv=dev\ -Dliquibase.url="jdbc:postgresql://dev/test?prepareThreshold=0&stringtype=unspecified" 

Geração de SQL sem atualizar o banco de dados


Às vezes, antes de iniciar as alterações, é necessário examinar o conteúdo das solicitações geradas. Os comandos liquibase: updateSQL e liquibase: rollbackSQL são para esse fim.


 #!/usr/bin/env bash mvn liquibase:updateSQL\ -Denv=dev\ -Dliquibase.url="jdbc:postgresql://dev/test?prepareThreshold=0&stringtype=unspecified" > /tmp/script.sql 

Mais sobre changeSet


As alterações podem estar em diferentes formatos, incluindo sql regular ou em um arquivo separado.


Cada alteração pode incluir uma seção de reversão que permite reverter as alterações com o comando liquibase: rollback . Além disso, você pode usar o tagDatabase para marcar alterações, por exemplo, para reverter para lá mais convenientemente.


Formato normal


 <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> 

SQL incorporado


 <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> 

Arquivo SQL


 <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> 

Iniciar contextos


Para um gerenciamento mais conveniente de várias configurações, por exemplo, desenvolvimento / produção, contextos podem ser usados. O contexto é especificado no atributo changeSet do contexto e, em seguida, iniciado pelo Maven com o parâmetro -Dcontexts.


Mudar com o contexto


 <changeSet context="legacy" author="author" id="1-initial-changeset"> <tagDatabase tag="initial"/> </changeSet> 

Disparando alterações de contexto


 #!/usr/bin/env bash mvn liquibase:update\ -Denv=dev\ -Dliquibase.url="jdbc:postgresql://dev/test?prepareThreshold=0&stringtype=unspecified"\ -Dliquibase.contexts=non-legacy 

Reverter alterações


A operação é o oposto da atualização, na maioria dos casos, é suportada automaticamente. Para outros, a tarefa é possível através da seção de reversão. É iniciado pelo comando liquibase: rollback.


Alterar com reversão


 <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> 

Iniciar reversão


 #!/usr/bin/env bash mvn liquibase:update\ -Denv=dev\ -Dliquibase.url="jdbc:postgresql://dev/test?prepareThreshold=0&stringtype=unspecified"\ -Dliquibase.contexts=non-legacy 

Comparação


No desenvolvimento, é conveniente usar para comparar dois bancos de dados existentes para as alterações feitas. Nas configurações (ou parâmetros de inicialização), você precisará adicionar um link ao banco de dados de referência e dados para acessá-lo.


liquibase.properties


 referenceUsername=test referenceUrl=jdbc:postgresql://dev/test_reference 

Comparação de circuitos


Comparando esquemas de URL e 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 

Salvando esquema


Também pode ser útil salvar o esquema atual do banco de dados, com ou sem dados. Deve-se ter em mente que o Liquibase salva um esquema que não corresponde totalmente ao original, por exemplo, os domínios usados ​​ou a herança precisam ser adicionados separadamente (consulte Restrições).


Salvando um esquema sem levar em consideração os dados


Salvando o esquema de um banco de dados existente.


 #!/usr/bin/env bash mvn liquibase:generateChangeLog\ -Denv=dev\ -Dliquibase.url="jdbc:postgresql://dev/test_reference?prepareThreshold=0"\ -Dliquibase.outputChangeLogFile=dev/changelog.xml 

Salvando um esquema com dados


Salvando o esquema de um banco de dados existente com dados.


 #!/usr/bin/env bash mvn liquibase:generateChangeLog\ -Denv=dev\ -Dliquibase.url="jdbc:postgresql://dev/test_reference?prepareThreshold=0"\ -Dliquibase.outputChangeLogFile=dev/changelog.xml 

Limitações e problemas


Trabalhando com dados binários no banco de dados


Existem alguns problemas com o upload, a comparação e o uso de dados binários, em particular um problema com a geração de alterações.



Herança e colunas comuns



Código fonte



Soluções alternativas


Via aérea


Junto com o Liquibase é popular na comunidade Java - http://flywaydb.org/documentation


Sqqitch


Equivalente a Perl - http://sqitch.org


Migrante fluente


Analógico para .Net - https://github.com/schambers/fluentmigrator


Dbgeni


Analógico para Ruby - http://dbgeni.appsintheopen.com/manual.html


Aplicações


Estrutura do projeto


 pom.xml - maven makefile dev liquibase.properties - login/password etc master.xml - changesets 

Como adicionar liquibase a um projeto existente



Como as alterações básicas funcionam



Mais sobre o formato de alteração



Mais sobre atualização



Mais sobre geração de mudanças



Mais sobre SQL personalizado



Processando tipos de dados específicos do banco de dados


 <createTable tableName="t_name"> ... <column name="doubleArray" type="DOUBLE_ARRAY"/> ... </createTable> <modifySql dbms="postgresql"> <replace replace="DOUBLE_ARRAY" with="double precision[][]"/> </modifySql> 

Outros


Source: https://habr.com/ru/post/pt436994/


All Articles