Versionado de esquemas de bases de datos y migraciones simplificadas para CI/CD de alta velocidad – PARTE 1

Actualización: Para ver la segunda parte de esta serie de artículos, haz clic aquí.

Si eres desarrollador de back-end, probablemente con cada nuevo despliegue te tengas que enfrentar a las migraciones del esquema de tu base de datos.

El framework llamado Liquibase puede facilitarte las cosas cuando necesites actualizar tu esquema de base de datos.

En este artículo explicaré cómo Liquibase puede emplearse en un proyecto Java, con Spring/Hibernate para versionar el esquema de la base de datos.

¿Cómo funciona Liquibase?

Registro de cambios

Liquibase trabaja con archivos de registro de cambios o Changelog (la lista de todos los cambios, en orden, que deben ejecutarse para actualizar la base de datos).

Hay 4 formatos soportados para estos changelogs: SQL, XML, YAML y JSON.

Conjuntos de cambios

Un conjunto o set de cambios representa un único cambio en tu base de datos.

Cada conjunto de cambios se identifica mediante atributos de “id” y “autor”, y por el directorio y nombre del archivo de registro de cambios, lo que permite identificarlo de manera única y aplicarlo una sola vez.

Cuando se ejecuta el registro de cambios, los conjuntos de cambios definidos en él se ejecutarán uno a uno, en el orden de definición.

Por lo tanto, si hay un error en un conjunto de cambios, todos los precedentes ya se habrán aplicado. Liquibase abortará esta ejecución en caso de error. De esta forma, solo tendrás que corregir el conjunto de cambios incorrecto, volver a activar Liquibase y continuar con tu migración. (Explicaré más adelante cómo Liquibase encuentra el conjunto de cambios desde el que debe continuar).

Tipos de cambios

Cada conjunto de cambios contiene uno o varios tipos de cambio, que describen qué tipos de operaciones se deben aplicar a la base de datos.

Liquibase admite tanto SQL en bruto, como tipos de cambio (que generan SQL para las bases de datos admitidas). Pero si quieres ejecutar el mismo registro de cambios en diferentes proveedores de bases de datos, es mejor usar tipos de cambios. Estos también permiten revertir los cambios en caso de error.

Generalmente, solo debería haber un tipo de cambio por cada conjunto de cambios, para evitar declaraciones de comprobación automática fallidas que puedan dejar la base de datos en un estado inesperado.

Retroceso a una versión anterior

Liquibase te permite deshacer errores que hayas introducido en tu base de datos, bien automáticamente (se generan por un tipo de cambio) o mediante versiones anteriores SQL personalizadas.

Debes incluir una cláusula de <rollback> en cada conjunto de cambios, cuando un cambio pueda revertirse (por ejemplo, <sql>, <insert>, <update> y otras modificaciones destructivas).

Por ejemplo, la etiqueta dropTable de Liquibase es una modificación destructiva, ya que no es posible añadir una tabla recuperando datos eliminados. En estos casos, la etiqueta de rollback no puede ser automática. Por lo tanto, debes gestionar el rollback o la reversión tú mismo para volver a la versión previa de tu base de datos.

Tablas de seguimiento

Si tu base de datos no contiene todavía tablas de seguimiento, Liquibase creará 2 tablas en ella cuando se ejecute: DATABASECHANGELOG y DATABASECHANGELOGLOCK.

  1. DATABASECHANGELOG

Cuando Liquibase se está ejecutando, consulta la tabla DATABASECHANGELOG para los conjuntos de cambios que están marcados como ejecutados y luego continúa con todos los que aún no se han realizado.

Después de cada ejecución de un conjunto de cambios, Liquibase lo registra en la tabla DATABASECHANGELOG. Una fila corresponde a un conjunto de cambios, identificado con una combinación única de las columnas de “id”, “author” (autor) y “filename” (nombre de archivo).

  1. filename

La columna de nombre de archivo puede ser:

  • una ruta absoluta
  • una ruta relativa dependiendo de cómo se ha pasado el registro de cambios a Liquibase
  • el valor del atributo logicalFilePath del registro de cambios
  • el valor del atributo logicalFilePath del conjunto de cambios
  • md5sum

Hay otra columna importante: md5sum. Como su nombre indica, comprueba que el contenido de un conjunto de cambios no se haya modificado desde su primera ejecución.

¡¡¡NUNCA modifiques un conjunto de cambios que ya ha sido aplicado!!!

2.    DATABASECHANGELOGLOCK

Para evitar conflictos de diferentes instancias de Liquibase, existe otra tabla: DATABASECHANGELOGLOCK.

A veces, el lock no se libera, si una instancia de Liquibase no se cierra limpiamente. Después de asegurarse de que todas las instancias de Liquibase están detenidas, puedes eliminar el lock actual ejecutando el siguiente comando SQL:

 UPDATE DATABASECHANGELOGLOCK SET LOCKED=0

Configuración

Dependencia de graduación

Empecemos con la dependencia de graduación que necesitamos añadir a nuestro build.gradle:

compile group: ‘org.liquibase’, name: ‘liquibase-core’, version: ‘3.9.0’

Árbol de registros de cambios

Ahora que ya conoces lo básico de Liquibase, voy a explicar cómo organizar tus registros o conjuntos de cambios.

Si quieres, puedes usar solo un registro de cambios, pero después de varias versiones, tu archivo será ilegible. Es mejor practicar para separar tus conjuntos de cambios en diferentes archivos.

El mejor método es tener 1 archivo por función + 1 carpeta por versión + 1 registro maestro de cambios que añada todos los registros de cambios con una etiqueta de include o includeAll.

Primero crea el archivo de registro de cambios maestro en la carpeta src/main/resources.

Para incluir los sub-registros de cambios, hay dos formas: usar etiquetas de include o includeAll

1. include

Debes especificar los registros de cambios uno a uno y se ejecutan en el orden en el que se encuentran.

Así que, si utilizas esta opción, necesitas prestar atención al orden de la declaración del registro de cambios, y no crear un bucle.

Si creas un bucle de registros de cambios (root.changelog.xml incluye sub.changelog.xml, que incluye root.changelog.xml), obtendrás un bucle infinito.

También puedes crear un registro de cambios maestro intermedio para todas las versiones, para evitar tener que enumerar todos los registros de cambios en el maestro raíz.

master -> 0.0.0/master, 1.0.0/master, 1.0.1/master

0.0.0/master -> 0.0.0/file1, 0.0.0/file2…

1.0.0/master -> 1.0.0/…

2. includeAll

Esta es similar a la etiqueta include, pero en lugar de pasar un archivo de registro de cambios específico para incluir, especificas un directorio en el que incluyes todos los archivos *.xml de registros de cambios y todos los archivos *.sql como cambios individuales.

Todos los archivos encontrados se ejecutan en orden alfabético. Así que debes emplear una convención de nomenclatura para que los archivos se ejecuten en el orden adecuado.

3. relativeToChangelogFile

Este atributo de include e includeAll calcula la ruta del archivo incluido (para la tabla de DATABASECHANGELOG) relativo al archivo de registro de cambios que contiene el archivo incluido, en lugar de la ruta de clasificación.

4. logicalFilePath

Este atributo de registro y conjunto de cambios anula el nombre del archivo y la ruta al crear el identificador único de los conjuntos de cambios.

Se necesita a la hora de mover o renombrar registros de cambios.

También puede ser útil cuando varias instancias de Liquibase utilizan la misma base de datos, pero la ruta de clasificación del registro de cambios que usan no es la misma.

Por ejemplo, puedes dividir tus registros de cambios en diferentes módulos de tu proyecto para probar tus repositorios / servicios de forma independiente. Pero también puedes tener tests finales cuando todos tus módulos / registros de cambios están empaquetados. Si la ruta de clasificación de tus registros de cambios en el envase no es la misma que en los módulos, Liquibase no reconoce los registros de cambios como iguales.

La mejor solución es tener diferentes bases de datos para los diferentes resultados, pero a veces, la compañía para la que trabajas se negará a ofrecer otra por el coste que supone.

Sin logicalFilePath

Con logicalFilePath

Esta es la primera entrega de este articulo, en la próxima entrega veremos mas detalles avanzados sobre este tema.

Actualización: Para ver la segunda parte de esta serie de artículos, haz clic aquí.

Escritora del articulo:

Souchet Céline, ingeniera de I+D en Bonitasoft

Desarrollador gráfico y web, con ganas de trabajar y aprender todo lo posible de este campo tan variado. Trato de ser creativo en la vida laboral como personal. Amante de la buena lectura, el cine con sentido e inteligente.

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *