Introduccion
Liquibase es un sistema de control de versión de base de datos, esto se refiere principalmente a la estructura y, en menor medida, al contenido de la base de datos. Al mismo tiempo, la descripción de la base de datos, por un lado, es bastante abstracta y permite el uso de varios DBMS en el nivel inferior, y por otro lado, siempre puede cambiar al dialecto SQL de un DBMS específico, que es bastante flexible. Liquibase es un proyecto de código abierto establecido y se utiliza activamente fuera de su entorno nativo de Java y no requiere un conocimiento profundo de Java para funcionar. Históricamente, se ha utilizado un formato XML para describir la estructura base y los cambios base, pero ahora YAML y JSON son compatibles en paralelo.
En este artículo, resumiremos brevemente la experiencia de generaciones anteriores y nos centraremos en trabajar con Liquibase utilizando Maven. Usaremos Ubuntu como sistema operativo de prueba.
Otros artículos sobre Liquibase
Entorno
Hay varias formas de iniciar Liquibase, sin embargo, es más conveniente usar Maven o Gradle.
sudo apt install maven mvn -version
Aquí pom.xml actúa como un Makefile: ya contiene todas las dependencias, configuraciones y perfiles necesarios.
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>
Lanzamos actualización
Después de haber hecho pom.xml, podemos comenzar a actualizar la base de datos, el comando liquibase: update.
Para esto necesitamos:
- Archivo liquibase.properties con configuraciones para conectarse a la base de datos (nombre de usuario / contraseña y posiblemente otros parámetros)
- archivo xml con cambios base
- script de inicio de actualización de base de datos sh
Archivo de configuración de conexión de base de datos
liquibase.properties
username=test password=test referenceUsername=test # #url=jdbc:postgresql://dev/test #referenceUrl=jdbc:postgresql://dev/test_reference
Archivo de cambios base
El concepto principal de liquibase son los llamados cambios de base (conjuntos de cambios). Pueden incluir cambios estructurales y cambios de datos. Liquibase utiliza las tablas databasechangelog y databasechangeloglock para monitorear los cambios aplicados.
<?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 inicio de actualización de base de datos
Aquí liquibase: la actualización se ejecuta para el perfil de desarrollo y la base de liquibase.url, que se especifica en el formato estándar JDBC. Después de la actualización, la tabla indicada en changeSet y dos tablas de servicio databasechangelog y databasechangeloglock aparecen en la base de datos .
#!/usr/bin/env bash mvn liquibase:update\ -Denv=dev\ -Dliquibase.url="jdbc:postgresql://dev/test?prepareThreshold=0&stringtype=unspecified"
Generación de SQL sin actualizar la base de datos.
A veces, antes de comenzar los cambios, debe mirar el contenido de las solicitudes generadas. Los comandos liquibase: updateSQL y liquibase: rollbackSQL están destinados para este propósito.
#!/usr/bin/env bash mvn liquibase:updateSQL\ -Denv=dev\ -Dliquibase.url="jdbc:postgresql://dev/test?prepareThreshold=0&stringtype=unspecified" > /tmp/script.sql
Más sobre el cambio
Los cambios pueden estar en diferentes formatos, incluyendo sql regular o en un archivo separado.
Cada cambio puede incluir una sección de reversión que le permite revertir los cambios con el comando liquibase: rollback . Además, puede usar tagDatabase para marcar cambios, por ejemplo, para retroceder allí de manera más conveniente.
<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>
Archivo SQL
<changeSet context="legacy" author="author" id="1-user"> <sqlFile dbms="postgresql" path="sql/some.sql" relativeToChangelogFile="true" /> <rollback> delete from "some"; </rollback> </changeSet>
Etiquetas
<changeSet context="legacy" author="author" id="1-initial-changeset"> <tagDatabase tag="initial"/> </changeSet>
Contextos de lanzamiento
Para una gestión más conveniente de varias configuraciones, por ejemplo, desarrollo / producción, se pueden usar contextos. El contexto se especifica en el atributo changeSet del contexto y luego Maven lo inicia con el parámetro -Dcontexts.
Cambiar con el contexto
<changeSet context="legacy" author="author" id="1-initial-changeset"> <tagDatabase tag="initial"/> </changeSet>
Disparo de cambios 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
Revertir cambios
La operación es lo opuesto a la actualización, en la mayoría de los casos es compatible automáticamente. Para otros, la tarea es posible a través de la sección de reversión. Es lanzado por el comando liquibase: rollback.
Cambiar con reversión
<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>
Lanzar reversión
#!/usr/bin/env bash mvn liquibase:update\ -Denv=dev\ -Dliquibase.url="jdbc:postgresql://dev/test?prepareThreshold=0&stringtype=unspecified"\ -Dliquibase.contexts=non-legacy
Comparación
En desarrollo, es conveniente usar para comparar dos bases de datos existentes para los cambios realizados. En la configuración (o parámetros de inicio), deberá agregar un enlace a la base de datos de referencia y los datos para acceder a ella.
liquibase.properties
referenceUsername=test referenceUrl=jdbc:postgresql://dev/test_reference
Comparación de circuitos
Comparación de los esquemas url y 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
Esquema de ahorro
También puede ser útil guardar el esquema de la base de datos actual, con o sin datos. Debe tenerse en cuenta que Liquibase guarda un esquema que no corresponde totalmente al original, por ejemplo, los dominios utilizados o la herencia deberán agregarse por separado (ver Restricciones).
Guardar un esquema sin tener en cuenta los datos
Guardar el esquema de una base de datos existente.
#!/usr/bin/env bash mvn liquibase:generateChangeLog\ -Denv=dev\ -Dliquibase.url="jdbc:postgresql://dev/test_reference?prepareThreshold=0"\ -Dliquibase.outputChangeLogFile=dev/changelog.xml
Guardar un esquema con datos
Guardar el esquema de una base de datos existente con datos.
#!/usr/bin/env bash mvn liquibase:generateChangeLog\ -Denv=dev\ -Dliquibase.url="jdbc:postgresql://dev/test_reference?prepareThreshold=0"\ -Dliquibase.outputChangeLogFile=dev/changelog.xml
Limitaciones y problemas
Trabajando con datos binarios en la base de datos
Existen ciertos problemas con la carga, comparación y uso de datos binarios, en particular, un problema con la generación de cambios.
Herencia y columnas comunes
Código fuente
Soluciones alternativas
Flyway
Junto con Liquibase es popular en la comunidad Java: http://flywaydb.org/documentation
Sqqitch
Perl equivalente - http://sqitch.org
Inmigrante fluido
Análogo para .Net - https://github.com/schambers/fluentmigrator
Dbgeni
Análogo para Ruby - http://dbgeni.appsintheopen.com/manual.html
Aplicaciones
Estructura del proyecto
pom.xml - maven makefile dev liquibase.properties - login/password etc master.xml - changesets
Cómo agregar liquibase a un proyecto existente
Cómo funcionan los cambios de base
Más acerca de la actualización
Más sobre la generación de cambios
Más información sobre SQL personalizado
Procesamiento de tipos de datos específicos de la base de datos
<createTable tableName="t_name"> ... <column name="doubleArray" type="DOUBLE_ARRAY"/> ... </createTable> <modifySql dbms="postgresql"> <replace replace="DOUBLE_ARRAY" with="double precision[][]"/> </modifySql>
Otros