DEV Community

Cover image for Flyway e Spring Boot em cenário de banco de dados não vazio.
Joaquim Chianca
Joaquim Chianca

Posted on

Flyway e Spring Boot em cenário de banco de dados não vazio.

Em um projeto de programação, em que estava construindo uma API com Spring Boot (Java), precisei adicionar alguns records numa tabela do meu banco de dados. Devido ao meu repertório e também buscando me desafiar, adicionei a dependência do Flyway para adicionar migrações ao meu banco de dados. Entretanto, ao adicionar o Flyway num projeto existente, ocorreram alguns comportamentos inesperados.

Mas, calma, tô voando.. O que é o Flyway?

Basicamente, o Flyway serve de versionamento de banco de dados. Suponha que existem 3 programadores rodando o mesmo projeto num ambiente de desenvolvimento. O ideal é que o banco de dados de todos (mesmo que em ambientes diferentes) possuam as mesmas tabelas.

Por meio de vários arquivos .sql, o Spring detecta a existência desses arquivos, roda o script SQL antes mesmo de criar as tabelas com o Hibernate. Assim, podemos criar arquivos .sql para criar as tabelas necessárias para o funcionamento correto da aplicação, garantindo que as tabelas possuem o mesmo formato para cada ambiente de desenvolvimento diferente. Uma forma de padronizar e manter o banco de dados atualizado para todos do time.

E Hibernate?

Hibernate é uma implementação da JPA (Java Persistence API), responsável pela ponte entre a sua aplicação e seu banco de dados. Todo método default do repository é implementado pelo Hibernate. O Hibernate também é o responsável por criar suas tabelas das entidades do seu projeto (classes anotadas com o @Entity).

O Hibernate já cria minhas tabelas, por qual razão eu preciso do Flyway?

Como já comentado acima, o Flyway é usado para padronizar as tabelas do seu projeto. Dessa forma, o Spring executa as migrações do Flyway antes mesmo de executar o Hibernate, logo, o ideal é que o time defina muito bem essas tabelas por meio de arquivos .sql no projeto.

A boa prática é criar as migrations antes mesmo de criar qualquer classe dentro do seu projeto.

Adicionando Flyway a um projeto existente

A motivação de escrever esse arquivo veio quando tentei adicionar o Flyway ao meu projeto que já possuía as tabelas mapeadas para cada entidade, criadas através do Hibernate.

Minha ideia era usar o Flyway apenas para inserir records numa tabela já existente, porém notei que as inserções não estavam acontecendo.

Dissecando o problema

Primeiro, fui atrás de criar novas migrations no projeto, para ter certeza de que o Flyway estava configurado corretamente e funcionando quando eu criava novas tabelas. E sim, ele funcionara corretamente quando foi criada uma tabela exemplo arbitrária.

Tendo em mente que o problema não estava na configuração da dependência externa, fui atrás de saber como funciona o relacionamento do Flyway com o Hibernate. O interessante (como já foi comentado nesse artigo) foi descobrir que o Flyway é executado antes do Hibernate. Dessa forma, era óbvio que minha lógica não funcionaria, afinal, como eu posso inserir records numa tabela que ainda não foi carregada pelo Hibernate?

O problema estava exatamente nessa ordem de execução das dependências.

Resolução

Bastou criar uma classe de configuração do Flyway para que fosse carregado o conteúdo do Hibernate antes do próprio Flyway. Para isso:

  1. Defini a propriedade spring.flyway.enabled=false no application.properties
  2. Criei uma classe de configuração Flyway FlywayConfig.java
@Configuration
public class FlywayConfig {

    @Autowired
    public FlywayConfig(DataSource dataSource) {
        Flyway.configure()
                .baselineVersion("0.0")
                .baselineOnMigrate(true)
                .dataSource(dataSource)
                .load().migrate();
    }
}
Enter fullscreen mode Exit fullscreen mode

O próprio Spring injeta o dataSource nesse construtor do Flyway, indicando que ele deve carregar primeiro o banco de dados .dataSource(dataSource).load() e apenas depois executar a migração, por meio do método migrate().

Feito isso, criei uma nova migration com inserção de records V4__insert_user.sql

insert into tb_user(id, email, name, password, username) values
(7, 'zeldris@gmail.com', 'zeldris', 'zeldris', 'zeldris');
Enter fullscreen mode Exit fullscreen mode

E voilà, a record está inserida na minha tabela:
tela mostrando a inserção

Conclusão

O intuito desse artigo é compartilhar essa noção de funcionamento das duas dependências que lidam com banco de dados: Hibernate e Flyway, além de ajudar aqueles que estão com o projeto existente e passam pela mesma situação de mal funcionamento das migrations da ferramenta.

Top comments (0)