Programación

Gestión de cambios de la base de datos – Liquibase

Una de las prácticas habituales en los desarrollos, es la creación de script sql incrementales. Con lo que comenzamos con script de creación de tablas, script de inserción de datos etc etc … y, a medida que avanza el desarrollo, cada uno de los desarrolladores va creando scripts con las modificaciones oportunas que le exige la tarea que está llevando a cabo. Esta práctica hace del proceso de cambios de base de datos un proceso totalmente manual, que puede llevar a confusiones, sobre todo debido a que es muy posible no saber que scripts se han ejecutado y cuales faltan por ejecutar en cada uno de los entornos que estemos manejando.

Una de las herramientas que nos puede hacer más sencillo estas modificaciones que se producen a la base de datos es Liquibase. Los scritps que actualizan la base de datos se definen en un XML (o json entre otros) de cambios que es independiente del sistema de base de datos que usemos aunque se pueden incluir sentencias SQL específicas para uno de ellos, también se pueden definir las sentencias rollback que permiten volver a un estado anterior. Soporta las principales bases de datos entre ellas: 

Liquibase es un librería Open Source (bajo licencia Apache 2.0), totalmente independiente del DBMS, que nos permitirá realizar el seguimiento, gestión y aplicación de cambios en el modelo de datos. Hoy en día, en cualquier desarrollo profesional de software no puede faltar un sistema de control de versiones. Esta práctica esta totalmente arraigada en los desarroladores que, sin embargo, en muy pocas ocasiones la usamos en cuanto al modelo de datos se refiere.

Liquibase es una librería diseñada para trabajar principalmente desde línea de comandos, pero también se integra muy fácilmente con Maven y Spring. Con ésta herramienta no tendremos que preocuparnos de estar ejecutando diferentes scripts, ni el orden en que se ejecutan. Además cada miembro del equipo de desarrollo dispondrá de información sobre que cambios se han realizado y quien los ha realizado.

Entorno

El tutorial está escrito usando el siguiente entorno:

Puesta en marcha

Antes de empezar me gustaría dejarles el enlace a la página oficial de la librería. Liquibase. En ella van a poder encontrar toda la documentación disponible sobre el proyecto ya que el objetivo del tutorial es darles a conocer esta librería y enseñarles como ponerla en marcha.

En nuestro caso no utilizaremos la librería de forma directa ya que decidí utilizar MAVEN y dicha herramienta ya posee un plugin para implementar Liquibase fácilmente, por más info, click aqui

Paso 1: Modificar el archivo pom.xml

Obs: Agregar la dependencia de PostgreSQL dentro del tag  dependencies y el plugin Liquibase dentro del tag build.


 <!-- PostgreSQL Java Connector -->
 <dependency>
 <groupId>org.postgresql</groupId>
 <artifactId>postgresql</artifactId>
 <version>9.2-1003-jdbc4</version>
 </dependency>

<!-- Plugin Liquibase -->

<build>
 <plugins>

<plugin>
 <groupId>org.liquibase</groupId>
 <artifactId>liquibase-maven-plugin</artifactId>
 <version>3.0.8</version>
 <configuration>
 <changeLogFile>src/main/resources/db/db.changelog-master.xml</changeLogFile>
 <driver>org.postgresql.Driver</driver>
 <username>username</username>
 <password>password</password>
 <url>jdbc:postgresql://localhost:5432/db</url>
 </configuration>
 <executions>
 <execution>
 <phase>process-resources</phase>
 <goals>
 <goal>update</goal>
 </goals>
 </execution>
 </executions>
 </plugin>

 </plugins>
 </build>

Los parámetros a modificar son:

<username>username</username> -> Usuario
<password>password</password> -> Contraseña
<url>jdbc:postgresql://localhost:5432/db</url> -> IP, PUERTO Y NOMBRE DE BASE DE DATOS.

Paso 2: Crear el arhivo db.changelog-master.xml dentro de un package «db» en la sección «Other Sources»

db.changelog-master.xml


<?xml version="1.0" encoding="UTF-8"?>
<databaseChangeLog
 xmlns="http://www.liquibase.org/xml/ns/dbchangelog/1.6"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog/1.6
 http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-1.6.xsd">

 <!-- <changeSet id="1" author="Rodrigo">
 <comment>Agregar tabla test_table para prueba</comment>
 <createTable tableName="test_table">
 <column name="id" type="bigserial">
 <constraints primaryKey="true" nullable="false"/>
 </column>
 <column name="name" type="varchar(50)">
 <constraints nullable="false"/>
 </column>
 </createTable>
 </changeSet>
-->

</databaseChangeLog>

Con eso ya está lista la implementación de Liquibase, como verán es muy sencilla, en el último archivo XML dejé comentado un ejemplo del uso del changelog, siempre debe de tener un id secuencial y el nombre del desarrollador, también es recomendado agregar comentarios.

Al ejecutar el proyecto los cambios en la base de datos se realizarán de forma directa, si se trabaja con cualquier control de versiones asegurarse de tener un responsable en la administración del archivo changelog para no tener conflictos.

Ahora quiero dejarles una base teórica de todo lo que se puede hacer con la herramienta Liquibase.

Liquibase Tags

Liquibase nos proporciona una serie de etiquetas con las que construir nuestro conjunto de cambios. Lo cierto es que es bastante intuitivo, y como veremos a lo largo del tutorial, tanto el nombre de las etiquetas, como el nombre de los atributos de las mismas nos van a dar pistas sobre cual es la operación que van a realizar.

En un primer momento, el hecho de tener que aprender un nuevo «lenguaje», distinto de SQL para realizar cambios en la base de datos es una característica de liquibase que no me gustó en un principio. Principalmente dudaba de si con las etiquetas que Liquibase nos proporciona, se podrían realizar todos los cambios que con SQL estamos acostumbrados a realizar, sobre todo aquellos cambios que pudiesen resultar más complejos.

Después de realizar las primeras pruebas las dudas se disiparon. Liquibase nos va a permitir en todo momento seguir trabajando con script SQL, con la ventaja añadida de que todos lo cambios quedaran reflejados en el histórico.


 <createTable tableName="client">
 <column name="id" type="int">
 <constraints primaryKey="true" nullable="false"/>
 </column>
 <column name="firstname" type="varchar(255)"/>
 <column name="lastname" type="varchar(255)"/>
 <column name="username" type="varchar(255)">
 <constraints unique="true" nullable="false"/>
 </column>
 <column name="testid" type="int" />
 </createTable>

<dropTable>

Nos permite eliminar una tabla en base de datos.


<dropTable tableName="client" schemaName="mySchema"/></p>

<addColumn>

Nos permite añadir una columna a una tabla.


 <addColumn tableName="client">
 <column name="firstname" type="varchar(255)"/>
 </addColumn> 

<renameColumn>

Nos permite renombrar una columna de una tabla.


 <renameColumn tableName="client"
 oldColumnName="fname" newColumnName="firstName"/>

<modifyColumn>

Nos permite modificar una columna de una tabla.


 <modifyColumn tableName="client">
 <column name="firstname" type="varchar(5000)"/>
 </modifyColumn>

<dropColumn>

Nos permite eliminar una columna de una tabla.


<dropColumn tableName="client" columnName="firstname"/>  

 

<sqlFile>

Nos permite ejecutar un script SQL dentro del proceso de migración de liquibase.


<sqlFile path="/Users/sgdiaz/liquibase/insertAutentiaMasterClients.sql" /> 

<include>

El principal uso de esta etiqueta es poder romper el fichero principal de cambios (changelogs.xml) en pedazos más manejables. Esto supone una gran ventaja ya que a medida que avanzan los desarrollos el número de modificaciones suele ser muy elevado.

Una buena práctica es trabajar con un fichero de cambios por sprint o por versión, en función de las necesidades. Algo como :


<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog/1.9"
xmlns:xsi="http://www.w3.org/01XMLSchemainstance"
xsi:schemaLocation="http:www.liquibase.org/xml/ns/dbchangelog/1.9 http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-1.9.xsd">

<include file="db/db.changelog-1.0.xml" />
</databaseChangeLog>

Liquibase-Funcionalidad

A continuación os muestro cuales son las funciones que podremos realizar con Liquibase:

Tras realizar el update el chageset se ejecuta correctamente pero nos damos cuenta de que nos hemos equivocado en el nombre de una de las columnas. Es fácil caer en el error de modificar el changeset directamente, lo que nos provocará el error anteriormente mencionado (Los MD5Sum son distintos).

La primera vez que ejecutemos este comando contra una base de datos Liquibase creará dos tablas en el schema correspondiente. Una llamada DATABASECHAGELOG y otra DATABASECHAGELOGLOCK. La primera es donde se guardaran todos los cambios y la segunda es usada por Liquibase para controlar que solo se realicen un conjunto de cambios al mismo tiempo.

Aunque la mejor manera de controlar los cambios en la base de datos es mediente la adición de conjuntos de cambios durante el desarrollo, hay ocasiones en que será muy valioso poder realizar diffs de distintas bases de datos, sobre todo cuando se está llegando al final del proyecto, pudiendo así comprobar que todos los cambios necesarios están incluidos en el changelog. Es importante tener en cuenta que la ejecución del diff solo está disponible desde la línea de comandos.

En la actualidad Liquibase realiza las siguientes comparaciones:

-Diferencias de versión
-Ausencia de tablas
-Ausencia de vistas
-Ausencia de columns
-Ausencia de primary keys
-Ausencia de unique constraints
-Ausencia de foreign Keys
-Ausencia de secuencias
-Ausencia de índices
-Diferencias en la definición de las columnas (data type, auto-increment, etc.)
-Diferencias en la definición de las vistas.

Esta funcionalidad de Liquibase es muy útil cuando empezamos a trabajar con una base de datos que ya tiene creadas una serie de tablas. De tal manera que podremos generar nuestro changelogs.xml a partir del modelo de datos existente. Eso si, hay que tener en cuenta que esta funcionalidad tiene actualmente algunas limitaciones, como por ejemplo que no exporta procedimientos almacenados, funciones y triggers.

Utilizando la información existente en el histórico y una base de datos existente, Liquibase puede generar documentación sobre los cambios realizados en base de datos.La documentación generada es al estilo JavaDoc.

Depenpdiendo del proceso de desarrollo y de las necesidades que tengamos a la hora de liberar versiones, es posible que no queramos utilizar Liquibase para realizar los cambios sobre la base de datos de manera directa.

Por esta razón tanto los comandos Update y Rollback tienen un «sql output» de modo que no se ejecute nada contra la base de datos sino que se genera un script.sql que el desarrollador ejecutará manualmente.

Conclusiones

Liquibase es una herramienta muy útil que da un valor añadido a los desarrollos. Hay que tener en cuenta que llevar control estricto sobre el modelo de datos es algo muy importante que no siempre se realiza con la rigurosidad que requiere. Por tanto Liquibase puede convertirse en la herramienta perfecta para llevar acabo esta tarea.

Salir de la versión móvil