Por José Luis Rodríguez Alonso
Cuando trabajas en un proyecto desde 0, siempre suele surgir la necesidad de guardar los cambios en el esquema de tu base datos como migraciones, de forma que, cuando la aplicación esté en producción, no tengas que ejecutar SQL a mano antes de publicar una nueva versión.
De las opciones que existen para Java, he probado Flyway y Liquibase . Las dos funcionan de una manera similar, crean una tabla en tu base de datos. donde almacenan el histórico de cambios y se encargan de ejecutar las migraciones que no aparezcan en ella.
Entre Flyway y Liquibase, me quedo con Liquibase por algunas características que lo hacen más versátil a la larga. Una de ellas es que nos permite escribir nuestras migraciones en formatos independientes de la base de datos, de forma que si por el motivo que sea decidimos cambiar de una base de datos a otra, solo es necesario cambiar el driver de conexión.
Como Spring Boot tiene soporte para Liquibase, lo único que debemos hacer es añadir la dependencia a nuestro pom.xml e indicar la ruta donde almacenamos las migraciones:
|
|
Nota: En este caso no es necesario indicar la versión, porque Spring Boot ya lo hace por nosotros, gracias al spring-boot-starter-parent
Ahora en el archivo de configuración application.yaml indicamos la ruta de las migraciones:
|
|
Por defecto, Spring Boot configura Liquibase con el archivo db/changelog/db.changelog-master.yaml, pero personalmente prefiero hacerlo en XML, porque el autocompletado en IntelliJ permite crearlos pulsando apenas un par de teclas.
Con Liquibase, podemos escribir nuestras migraciones en varios formatos, sql, yaml, json, xml… Como dije antes, prefiero usar el xml, porque aunque es mucho más verboso, el autocompletado en IntelliJ es una maravilla.
El archivo liquibase-changelog.xml que definimos antes, contiene los ficheros que contienen nuestras migraciones. Tiene este formato:
<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.8.xsd">
<include file="changelog/changelog-v0.0.1.xml" relativeToChangelogFile="true"/>
</databaseChangeLog>
Aunque no es estrictamente necesario, yo prefiero organizar las migraciones en distintos ficheros, uno para cada versión de nuestra aplicación. Al principio, puede parecer innecesario, pero a la larga tener esto organizado es una ventaja.
Los archivos de las migraciones tienen esta forma:
<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.8.xsd">
<changeSet id="create-products-table" author="jrodalo">
<createTable tableName="products">
<column name="id" type="integer">
<constraints primaryKey="true"/>
</column>
<column name="name" type="varchar(255)"/>
</createTable>
</changeSet>
</databaseChangeLog>
Podemos añadir tantos changesets como necesitemos y cada changeset puede contener los cambios que quieras. En el ejemplo anterior, estaríamos creando una tabla products con un par de campos.
Las migraciones se ejecutan automáticamente al arrancar la aplicación. Spring Boot se encarga de ejecutar Liquibase y este se encarga de revisar el estado de las migraciones. Si existen cambios, los ejecutará por nosotros.
De esta forma, si necesitamos añadir una nueva tabla o campo a nuestra base de datos, solo debemos añadir la migración y desplegar los cambios.
Para probar que esto funciona, vamos a tirar de TestContainers. En nuestro archivo de configuración local, añadimos la configuración para PostgreSQL:
|
|
Nota: driver-class-name solo es necesario para versiones de Spring Boot anteriores a la 2.3.0
Y la dependencia en nuestro pom.xml:
|
|
Lo siguiente sería crear un test de integración con @SpringBootTest e intentar acceder a nuestra nueva tabla, algo como esto valdría:
|
|
Si ejecutamos el test y revisamos la consola, veremos que Spring Boot inicia la aplicación y, después de que Testcontainers arranque nuestra base de datos, Liquibase se encarga de crear nuestro esquema.
|
|
Aunque es poco probable que en un proyecto se decida cambiar la base de datos, es posible que necesitemos realizar una app que el cliente pueda personalizar y desplegar en sus propios servidores. Con Liquibase, eso lo podemos hacer simplemente cambiando el driver de conexión en nuestro pom.xml. Si cambiamos el driver de PostreSQL por el de MariaDB, Liquibase se encargará de traducir nuestras migraciones al SQL específico para esa base de datos.
¿Quieres más? te invitamos a suscribirte a nuestro boletín para avisarte cada vez que recopilemos contenido de calidad que compartir.
Si disfrutas leyendo nuestro blog, ¿imaginas lo divertido que sería trabajar con nosotros? ¿te gustaría?
Pero espera 🖐 que tenemos un conflicto interno. A nosotros las newsletter nos parecen 💩👎👹 Por eso hemos creado la LEAN LISTA, la primera lista zen, disfrutona y que suena a rock y reggaeton del sector de la programación. Todos hemos recibido newsletters por encima de nuestras posibilidades 😅 por eso este es el compromiso de la Lean Lista