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