Una de las asignaturas pendientes dentro del ciclo de vida de los proyectos es la gestión del versionado de los scripts de base de datos. En nuestra trayectoria, nos hemos encontrado con clientes que exigen una gestión compleja de cualquier tipo de cambio, pero siempre de forma manual, bajo documentos de procedimientos que no ayudan a una gestión ágil.

Para intentar dinamizar y controlar de forma sencilla estas modificaciones, hemos incluido en nuestro ecosistema de desarrollo la herramienta Liquibase. Aquí os dejamos un breve tutorial.

 

¿PARA QUÉ SIRVE?

Nos permite mantener el control de todos los cambios ejecutados sobre la base de datos, almacenando toda la información de los mismos (autor, fecha, cambio, etc.), asociando dichos cambios a los desarrollos realizados sobre la aplicación e integrándolos con el propio control de versiones del código fuente.

Por ejemplo: una rama de desarrollo tiene asociados sus correspondientes cambios de base de datos, lo cuales se integrarán con los demás cambios de otras ramas para permitir la unificación y generación de un solo script de base de datos sin que ello implique conflictos en el modelo de datos.

 

¿CÓMO FUNCIONA?

Su funcionamiento es sencillo y, sobre todo, compatible con múltiples arquitecturas de proyectos, siempre dependiendo de cómo se encuentre montado el proyecto. Básicamente actúa de la siguiente forma:

  1. Ejecución. Ya sea de forma manual (lanzando tú mismo la ejecución por comando Maven, Ant o por linea de comandos) o automática (Spring, Servlet, Hibernate, otros).
  2. Lectura de ficheros. Todos los cambios en base de datos los guardas en ficheros que Liquibase llama Changelogs, los cuales veremos más adelante. Estos ficheros son leídos durante la ejecución para determinar que cambios se deben aplicar en tu base de datos.
  3. Comparación con tu base de datos. Una vez Liquibase sepa qué cambios existen en tus changelogs, los cruza con su tabla interna llamada DATABASECHANGELOG, la principal tabla principal de versiones/cambios que se crea durante la primera ejecución. Así determina qué cambios debe aplicar y en qué versión se encuentra tu base de datos.
  4. Aplicación de cambios. Cuando tengas claros los cambios a aplicar, ejecútalos y actualiza la tabla de versiones/cambios. Si se produce algún error SQL durante la ejecución, mostrará el correspondiente mensaje y no actualizará la tabla de versiones/cambios.

 

¿QUÉ ES UN CHANGELOG?

Como ya hemos comentado, un changelog es un fichero que contiene todos los cambios que quieres aplicar en tu base de datos. Estos ficheros pueden ser XML (el más común), YAML, JSON o SQL. Aquí algunos ejemplos:

XML

<databaseChangeLog
    xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
    xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.1.xsd
    http://www.liquibase.org/xml/ns/dbchangelog-ext http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd">
	<changeSet author="liquibase-docs" id="createTable-example">
    <createTable catalogName="cat"
            remarks="A String"
            schemaName="public"
            tableName="person"
            tablespace="A String">
        <column name="address" type="varchar(255)"/>
    </createTable>
</changeSet>
</databaseChangeLog>

 

YAML

databaseChangeLog:
changeSet:
  id: createTable-example
  author: liquibase-docs
  changes:
  - createTable:
      catalogName: cat
      columns:
      - column:
          name: address
          type: varchar(255)
      remarks: A String
      schemaName: public
      tableName: person
      tablespace: A String

 

JSON

{
    "databaseChangeLog": [
"changeSet": {
    "id": "createTable-example",
    "author": "liquibase-docs",
    "changes": [
      {
        "createTable": {
          "catalogName": "cat",
          "columns": [
            {
              "column": {
                "name": "address",
                "type": "varchar(255)"
            }]
          },
          "remarks": "A String",
          "schemaName": "public",
          "tableName": "person",
          "tablespace": "A String"
      }]
  }
    ]
}

 

SQL

--liquibase formatted sql

--changeset nvoxland:1
create table test1 (
    id int primary key,
    name varchar(255)
);
--rollback drop table test1;

--changeset nvoxland:2
insert into test1 (id, name) values (1, ‘name 1′);
insert into test1 (id, name) values (2, ‘name 2′);

--changeset nvoxland:3 dbms:oracle
create sequence seq_test;

 

¿QUÉ PUEDO INCLUIR DENTRO DE UN CHANGELOG?

Liquibase interpreta que cada cambio en la base de datos se encuentra determinado por los changeset’s. Éstos no son más que las etiquetas (distinguidas en los ejemplos anteriores) que utiliza la herramienta para determinar un cambio asociado a un autor.

Un changelog puede tener uno o varios changesets, todo depende de la forma en la que se quieran organizar los cambios.

Dentro de una etiqueta changeset puedes incluir prácticamente cualquier cambio en base de datos, para ello utiliza las etiquetas que proporciona. También puedes importar ficheros SQL dentro de tus propios changelogs, mediante la etiqueta <include>.

 

¿CÓMO PUEDO CONFIGURAR MI PROYECTO MAVEN?

Lo primero que se debes hacer es incluir el plugin en el fichero pom.xml que permitirá ejecutar Liquibase en el proyecto:

<plugin>
      <groupId>org.liquibase</groupId>
      <artifactId>liquibase-maven-plugin</artifactId>
      <version>3.0.5</version>
      <configuration>
        <changeLogFile>src/main/resources/org/liquibase/db.changelog-master.xml</changeLogFile>
          <driver>oracle.jdbc.driver.OracleDriver</driver>
          <url>jdbc:oracle:thin:@tf-appserv-linux:1521:xe</url>
          <username>liquibaseTest</username>
          <password>pass</password>
        </configuration>
      <executions>
        <execution>
          <phase>process-resources</phase>
          <goals>
            <goal>update</goal>
          </goals>
        </execution>
      </executions></plugin>

 

Deberás tener en cuenta que desde el proyecto debes incluir la correspondiente librería JDBC que permita la conexión con la base de datos: mysql-connector-java, ojdbc14, etc.

Liquibase permite la conexión a tu base de datos por medio de un datasource definido en el entorno de Spring, pero ello obliga a que la ejecución se realice de forma automática en el arranque de la aplicación. Puedes encontrar más información en este enlace.

Lo siguiente será definir tu estructura de ficheros changelogs. Mientras dispongas de un fichero “máster” definido como fichero de inicio, Liquibase te da libertad completa a la hora de gestionar la organización de los ficheros. Sin embargo, y siguiendo la filosofía de control de versiones, existen buenas prácticas en este tema.

 

ESTRUCTURA DEL DIRECTORIO DE FUENTES JAVA

com
  example
    db
      changelog
        db.changelog-master.xml
        db.changelog-1.0.xml
        db.changelog-1.1.xml
        db.changelog-2.0.xml
      DatabasePool.java
      AbstractDAO.java

 

FICHERO DB.CHANGELOG-MASTER.XML

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

  <include file="com/example/db/changelog/db.changelog-1.0.xml"/> 
  <include file="com/example/db/changelog/db.changelog-1.1.xml"/> 
  <include file="com/example/db/changelog/db.changelog-2.0.xml"/> 
</databaseChangeLog>

 

FICHEROS DB.CHANGELOG-…

<?xml version="1.0" encoding="UTF-8"?> 
<databaseChangeLog 
  xmlns="http://www.liquibase.org/xml/ns/dbchangelog/1.9" 
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
  xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog/1.9
                      http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-1.9.xsd"> 
  <changeSet author="authorName" id="changelog-1.0">
    <createTable tableName="TablesAndTables">
      <column name="COLUMN1" type="TEXT">
        <constraints nullable="true" primaryKey="false" unique="false"/>
      </column>
    </createTable>
  </changeSet>
</databaseChangeLog>

 

Una vez definidos tus ficheros, ya puedes lanzar la ejecución mediante el correspondiente comando maven:

mvn liquibase:update

 

¿Y SI YA TENGO UNA BASE DE DATOS EXISTENTE?

Liquibase permite la generación automática de todos los changelogs necesarios basándose en una base de datos ya existente. Para ello, debes descargar los ejecutables (línea de comandos) y lanzarlos mediante el siguiente comando:

liquibase --driver=oracle.jdbc.OracleDriver \
      --classpath=\path\to\classes:jdbcdriver.jar \
      --changeLogFile=com/example/db.changelog.xml \
      --url="jdbc:oracle:thin:@localhost:1521:XE" \
      --username=scott \
      --password=tiger \
      generateChangeLog

 

Una vez haya finalizado el proceso, deberás haber generado en la ruta indicada todos los ficheros changelogs asociados al modelo completo de tu base de datos: tablas, indices, claves ajenas, etc.

Actualmente el comando generateChangeLog tiene la limitación de no exportar los siguientes tipos de objetos concretos: stored procedures, functions, packages, triggers.

 

¿DISPONGO DE OTRAS OPCIONES DE CONFIGURACIÓN?

Como dijimos anteriormente, además de Maven, puedes configurar la ejecución de Liquibase tanto manual como automáticamente dependiendo de la estructura/tecnologías del proyecto. Si necesitas más información, consulta este enlace.

 

 ¿ALGUNA OTRA CARACTERÍSTICA DESTACABLE?

Podemos destacar la posibilidad de configuración mediante entornos (producción, test, etc.), el hecho de que es independiente de la base de datos (una vez definidos los ficheros se pueden ejecutar sobre todos los motores de base de datos soportados) y su repositorio de plugins que permiten completar su funcionalidad.

 

¿ALTERNATIVAS A LIQUIBASE?

En nuestro caso, nos hemos decantado por Liquibase principalmente por dos motivos: porque abarca prácticamente todo el ciclo de vida de la gestión de la configuración, y por la versatilidad que ofrece para cualquier arquitectura. No obstante, si estos argumentos no te convencen, te recomendamos que sondees estas alternativas:

  • Rails Migrations (Ruby on Rails)
  • DBVersion
  • dbvcs
  • BSourceTools
  • Teamwork (Oracle y SQL Server)
  • Optim Database Administrator (DB2)