Aprofundando um pouco mais no Liquibase

No nosso post anterior vimos como o Liquibase pode nos ajudar a ter uma vida mais fácil com o versionamento dos nossos scripts de banco de dados. Agora a ideia é explorar algumas outras funcionalidades e entender melhor a estrutura que ele cria para fazer esse gerenciamento. Portanto, caso você nunca tenha visto o Liquibase, seria interessante dar uma olhada no nosso primeiro passo na ferramenta(abaixo).

Usaremos o mesmo codebase do post anterior, mas para ficar mais fácil a visualização, dessa vez utilizaremos PostgreSQL no lugar do H2.

Para que nossa vida seja muito mais fácil, vamos subir um container Docker com PostgreSQL na nossa máquina local. (Se você preferir, pode usar um banco já instalado na sua máquina. O importante é conseguir conectar corretamente).

1. Subir o Postgres. (via docker-compose)

Executar o comando

Crie o arquivo postgres_docker-compose.yml

### Execute ###
#docker-compose -f postgres_docker-compose.yml up -d
version: '2'
services:
postgres:
image:
postgres:9.6-alpine
hostname: postgres
ports:
- "5432:5432"
environment:
- POSTGRES_DB=liquibase-db
container_name: postgres
docker-compose -f postgres_docker-compose.yml up -d

2. Agora vamos fazer os devidos ajustes na aplicação.

O primeiro passo vai ser alterar a dependência no pom.xml. Vamos tirar a dependência do H2 e adicionar a do PostgreSQL

      <dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<scope>runtime</scope>
</dependency>

O próximo passo é atacar o application.yml e substituir as configurações ficando da seguinte forma:

project.name: aprofundando-no-liquibase

spring:
application:
name:
${project.name}

datasource:
url:
jdbc:postgresql://localhost/liquibase-db
username: postgres
password: postgres

jpa:
database:
postgresql
database-platform: org.hibernate.dialect.PostgreSQLDialect
hibernate:
ddl-auto:
validate
show-sql: true

E agora um pequeno ajuste no nosso script SQL. Primeiro vamos adequar ao novo BD e depois vamos dividir em duas changesets diferentes para visualizarmos melhor as atividades. No final ele ficará assim:

--liquibase formatted sql

--changeset marcopollivier:1
CREATE SEQUENCE IF NOT EXISTS hibernate_sequence;

CREATE TABLE IF NOT EXISTS product (
id BIGINT NOT NULL CONSTRAINT product_pkey PRIMARY KEY ,
description VARCHAR(255),
name VARCHAR(255),
parent_product_id BIGINT CONSTRAINT product_parent_fkey references product
);
--rollback ALTER TABLE product DROP CONSTRAINT product_parent_fkey;
--rollback DROP TABLE product;
--rollback DROP SEQUENCE hibernate_sequence;

--changeset outrousuario:2
CREATE TABLE IF NOT EXISTS image (
id BIGINT NOT NULL CONSTRAINT image_pkey PRIMARY KEY,
type VARCHAR(255),
product_id BIGINT CONSTRAINT product_image_fkey REFERENCES product
);
--rollback ALTER TABLE image DROP CONSTRAINT product_image_fkey;
--rollback DROP TABLE image;

Por partes. Primeiro simplificamos a linha das PKs (ids) de acordo com o dialeto do PostgreSQL. Mas a parte mais importante fica por conta dos changesets. Antes ficava tudo num único bloco. Agora separamos em 2. O primeiro feito pelo usuario marcopollivier e o outro pelo outrousuario.

Ah. Uma última alteração. Nas classes de modelo, mudamos o tipo do gerenciamento automático de ID. Agora ele está como AUTO

@GeneratedValue(strategy = GenerationType.AUTO)

E nesse momento chegamos exatamente ao ponto do post anterior, mas com o PostgreSQL configurado como banco da aplicação.

Agora podemos seguir em frente…


Estrutura das tabelas de metadados

Como chegamos a mencionar no post anterior, o Liquibase usa uma tabela própria para guardar metadados e assim saber como fazer o controle da versão das changes. Assim ficou a estrutura com todas as tabelas criadas:

O Liquibase criou duas tabelas para o gerenciamento das changes: databasechangeloglock e databasechangelog. A primeira serve para lockar possíveis alterações. Já a segunda é onde ficam guardadas todas as informações referentes as chagesets executadas. Essa é sua estrutura:

E essas são algumas informações que ela guarda para fazer o gerenciamento das alterações: (Elas são persistidas normalmente na tabela, mas eu retornei como JSON para facilitar a visualização)

SELECT row_to_json(r) FROM (select * from databasechangelog) r
{
"id": "1",
"author": "marcopollivier",
"filename": "classpath:/db/changelog/migrations/001_schema_inicial.sql",
"dateexecuted": "2018-01-29T21:41:57.680814",
"orderexecuted": 1,
"exectype": "EXECUTED",
"md5sum": "7:f07ef60abb63aa0393a87354fb182450",
"description": "sql",
"comments": "",
"tag": null,
"liquibase": "3.5.3",
"contexts": null,
"labels": null,
"deployment_id": "7269317658"
}

{
"id": "2",
"author": "outrousuario",
"filename": "classpath:/db/changelog/migrations/001_schema_inicial.sql",
"dateexecuted": "2018-01-29T21:41:58.041879",
"orderexecuted": 2,
"exectype": "EXECUTED",
"md5sum": "7:6e7aae4fbf618f377f8e63a174dc8239",
"description": "sql",
"comments": "",
"tag": null,
"liquibase": "3.5.3",
"contexts": null,
"labels": null,
"deployment_id": "7269317658"
}

Integrando o Liquibase com Maven

É possível rodar as ações adicionais do Liquibase adicionando um plugin dentro do pom.xml da nossa aplicação.

<plugin>
<groupId>org.liquibase</groupId>
<artifactId>liquibase-maven-plugin</artifactId>
<configuration>
<propertyFile>src/main/resources/db/changelog/db.changelog-master.yaml</propertyFile>
<changeLogFile>src/main/resources/db/changelog/db.changelog-master.yaml</changeLogFile>
</configuration>
</plugin>

Ao adicionar o plugin do Liquibase ao nosso pom.xml, essas são algumas funcionalidades que podemos utilizar a partir de agora.

Como não é possível (num primeiro momento) que o Maven enxergue as configurações dentro do application.yml do Spring, vamos adicionar no arquivos de propriedades do Liquibase as seguintes informações referentes a conexão com o banco de dados.

url: jdbc:postgresql://localhost/liquibase-db
username: postgres
password: postgres
driver: org.postgresql.Driver

Portanto nosso db.changelog-master.yaml completo ficará da seguinte forma:

url: jdbc:postgresql://localhost/liquibase-db
username: postgres
password: postgres
driver: org.postgresql.Driver

databaseChangeLog:
- include:
file:
migrations/001_schema_inicial.sql
relativeToChangelogFile: true

Com tudo configurado, vamos começar a brincar com os comandos do Liquibase.

Fazendo um update na base

No primeiro momento vamos fazer um update na tabela de imagem adicionando uma coluna description. Para isso basta adicionar o seguinte changeset no nosso arquivo .sql.

--changeset marcopollivier:3
ALTER TABLE image ADD COLUMN description VARCHAR(1024);
--rollback ALTER TABLE image DROP COLUMN description;

E então basta executar o seguinte comando:

mvn liquibase:update

O plugin fará seu trabalho e adicionará a coluna na tabela image. Agora vamos ver o resultado.

E na nossa tabela de changesets, tamos o nosso novo registro

{
"id":"3",
"author":"marcopollivier",
"filename":"src/main/resources/db/changelog/migrations/001_schema_inicial.sql",
"dateexecuted":"2018-01-30T00:12:23.539533",
"orderexecuted":3,
"exectype":"EXECUTED",
"md5sum":"7:357fc0604a706ee7aa38c5ef39500f14",
"description":"sql",
"comments":"",
"tag":null,
"liquibase":"3.5.3",
"contexts":null,
"labels":null,
"deployment_id":"7278343520"
}

Pronto. A alteração na base foi feita com sucesso.

Rollback de um changeset

Bem. Já criamos uma estrutura completa. Já a alteramos. Que tal agora se nós desfizermos a alteração que acabamos de implantar. Vamos pensar que em um cenário real, não podemos deixar a alteração que acabamos de fazer. O que fazer? Usar o plugin do Liquibase para dar rollback no passo que acabamos de dar. Para isso, basta executar

mvn liquibase:rollback -Dliquibase.rollbackCount=1

Esse comando fará o rollback do changeset mais recente. Caso tivesse definido o rollbackCount=2, ele faria dos dois mais recentes e assim por diante.

Existem outras formas de fazer rollback, por exemplo:

mvn liquibase:rollback -Dliquibase.rollbackDate=Jun 03, 2017
mvn liquibase:rollback -Dliquibase.rollbackTag=1.0

Conclusão

A ideia desse post foi demonstrar alguns outros recursos que ganhamos quando começamo a utilizar o Liquibase nas nossas aplicações. Espero que tenha sido proveitoso.

Caso ainda tenha alguma dúvida, recomendo olhar a documentação oficial no site do Liquibase ou nesse post do baeldung que também fala sobre o assunto.

Não deixe de baixar o código no nosso Github: https://github.com/ResponsiveBR/aprofundando-um-pouco-mais-no-liquibase