Versionando o banco de dados com Flyway
Tags: java, spring, flyway
Published: 2021-06-18 15:32:38

---
title: Versionando o banco de dados com Flyway
published: true
date: 2021-01-11 00:00:01 UTC
tags: java, spring, flyway
canonical_url: https://programadev.com.br/flyway-java/
---

Bancos de dados são ferramentas importantíssimas que são utilizadas na construção de aplicações, existem muitas opções de bancos de dados disponíveis e cada uma atende a uma necessidade específica. Com o advento dos microsserviços e a ideia de cada aplicação administrar o seu próprio estado, os bancos de dados confirmam a sua importância.

Mas criar, atualizar e deletar colunas e tabelas não é uma tarefa das mais simples em grandes aplicações ou com cenários complexos, o **Flyway** surge como uma ferramenta para facilitar as migrações e o versionamento nos bancos de dados.

Contudo o **Flyway** não é um bala de prata e nem tem a intenção de substituir a função de um **DBA** , o **FLyway** é uma ferramenta para nos ajudar no dia-a-dia.

## Adicionando o Flyway no projeto[<svg aria-hidden="true" focusable="false" height="16" version="1.1" viewbox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg>](#Adicionando-o-Flyway-no-projeto)

Vou adicionar o **Flyway** em um [projeto](https://github.com/guilhermegarcia86/kafka-series/tree/flyway/register) que já existe e utiliza o **MySQL** como repositório de dados.

É uma aplicação **Java** com **Maven** então é só adicionar a dependência no `pom.xml`:

```xml
<!-- Flyway -->
<dependency>
    <groupId>org.flywaydb</groupId>
    <artifactId>flyway-core</artifactId>
</dependency>
```

## Configurando Properties[<svg aria-hidden="true" focusable="false" height="16" version="1.1" viewbox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg>](#Configurando-Properties)

É necessário configurar os dados de conexão do banco no **Flyway**. Como estamos usando **Spring Boot** podemos adicionar isso no arquivo `application.yml`:

```yml
spring:
  flyway:
    url: jdbc:mysql://${DATABASE_HOST:localhost}:${DATABASE_PORT:3306}/${DATABASE:register}?createDatabaseIfNotExist=true
    user: ${DATABASE_USER:root}
    password: ${DATABASE_PASSWD:root}
    schemas:
    - ${DATABASE:register}
```

Aqui configuramos a `url`, `user`, `password` e o `schema` que o **Flyway** irá usar para se conectar no banco de dados.

## Adicionando os Scripts[<svg aria-hidden="true" focusable="false" height="16" version="1.1" viewbox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg>](#Adicionando-os-Scripts)

Vamos adicionar os scripts que o **Flyway** irá rodar, para isso precisamos criar a pasta dentro de `resources` na nossa aplicação, por padrão o **Flyway** irá procurar pelo caminho `resources/db/migration` então basta criar os diretórios e adicionar os scripts.

Outro padrão do **Flyway** para gerenciamento de versão dos scripts é a convenção de nomenclatura dos arquivos, eles seguem o padrão **V** seguido do número da versão acompanhado de `underline` exemplo:

`V1_1__meu-script.sql`

Para essa aplicação vamos ter dois scripts iniciais, um para criar as tabelas e outro para executar a carga inicial:

`V1_0__create_tables.sql`:

```sql
create table perfil (
    id integer not null auto_increment,
    name varchar(255),
    primary key (id)
) engine=InnoDB;

create table user (
    id integer not null auto_increment,
    email varchar(255),
    pass varchar(255),
    primary key (id)
) engine=InnoDB;

create table user_perfis (
    user_id integer not null,
    perfis_id integer not null,
    primary key (user_id, perfis_id)
) engine=InnoDB;

alter table user_perfis add constraint perfil_id_constraint foreign key (perfis_id) references perfil (id);

alter table user_perfis add constraint user_id_constraint foreign key (user_id) references user (id);
```

`V1_1__init.sql`:

```sql
INSERT INTO register.`user`
(email, pass)
VALUES('jonhdoe@email.com', '$2a$10$JgDI7KttG8BX9AO.3mGTref9mjDxHKtx3sjqnaP3Vq88BzUNxA38S');

INSERT INTO register.perfil
(name)
VALUES('USER');

INSERT INTO register.perfil
(name)
VALUES('ADMIN');

INSERT INTO register.user_perfis
(user_id, perfis_id)
VALUES(1, 1);
```

## Executando o Flyway[<svg aria-hidden="true" focusable="false" height="16" version="1.1" viewbox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg>](#Executando-o-Flyway)

Quando iniciamos a nossa aplicação o **Flyway** é automaticamente iniciado e executa os scripts, a saída no console da aplicação é parecido com isso:

```bash
INFO 77800 --- [restartedMain] o.f.c.internal.license.VersionPrinter : Flyway Community Edition 7.1.1 by Redgate
INFO 77800 --- [restartedMain] o.f.c.i.database.base.DatabaseType : Database: jdbc:mysql://localhost:3306/register (MySQL 8.0)
INFO 77800 --- [restartedMain] o.f.core.internal.command.DbValidate : Successfully validated 2 migrations (execution time 00:00.152s)
INFO 77800 --- [restartedMain] o.f.c.i.s.JdbcTableSchemaHistory : Creating Schema History table `register`.`flyway_schema_history` ...
INFO 77800 --- [restartedMain] o.f.core.internal.command.DbMigrate : Current version of schema `register`: << Empty Schema >>
INFO 77800 --- [restartedMain] o.f.core.internal.command.DbMigrate : Migrating schema `register` to version "1.0 - create tables"
INFO 77800 --- [restartedMain] o.f.core.internal.command.DbMigrate : Migrating schema `register` to version "1.1 - init"
INFO 77800 --- [restartedMain] o.f.core.internal.command.DbMigrate : Successfully applied 2 migrations to schema `register` (execution time 00:00.625s)
```

Aqui podemos ver a mensagem de que o script foi executado com sucesso, mas o que acontece se executarmos a nossa aplicação novamente?

```bash
INFO 78443 --- [restartedMain] o.f.c.internal.license.VersionPrinter : Flyway Community Edition 7.1.1 by Redgate
INFO 78443 --- [restartedMain] o.f.c.i.database.base.DatabaseType : Database: jdbc:mysql://localhost:3306/register (MySQL 8.0)
INFO 78443 --- [restartedMain] o.f.core.internal.command.DbValidate : Successfully validated 2 migrations (execution time 00:00.115s)
INFO 78443 --- [restartedMain] o.f.core.internal.command.DbMigrate : Current version of schema `register`: 1.1
INFO 78443 --- [restartedMain] o.f.core.internal.command.DbMigrate : Schema `register` is up to date. No migration necessary.
```

Podemos ver que os scripts são validados porém o **Flyway** consegue gerenciar se o script já foi executado, isso acontece graças a tabela _flywayschemahistory_ que guarda as informações dos scripts executados:

```bash
| instaled_rank | version | description | type | script | checksum | installed_by | installed_on | execution_time | success |
|---------------|---------|---------------|------|-------------------------|-------------|--------------|---------------------|----------------|---------|
| 1 | 1.0 | create tables | SQL | V1_0__create_tables.sql | 1225588812 | root | 2021-01-11 17:57:36 | 460 | 1 |
| 2 | 1.1 | init | SQL | V1_1__init.sql | -1406395169 | root | 2021-01-11 17:57:36 | 27 | 1 |
```

Essa tabela trás informações que servem para o **Flyway** se gerenciar e gerenciar os scripts.

## Flyway em um banco já populado[<svg aria-hidden="true" focusable="false" height="16" version="1.1" viewbox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg>](#Flyway-em-um-banco-ja-populado)

Se adicionarmos o **Flyway** em uma aplicação que já possui um banco de dados populado ocorrerá um erro, mas podemos resolver isso com uma configuração simples no `application.yml`:

```yml
spring:
  flyway:
    baseline-on-migrate: true
```

## Código fonte[<svg aria-hidden="true" focusable="false" height="16" version="1.1" viewbox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg>](#Codigo-fonte)

Segue o código no [GitHub](https://github.com/guilhermegarcia86/kafka-series/tree/flyway/register)