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:
- Defini a propriedade
spring.flyway.enabled=false
noapplication.properties
- 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(); }
}
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, '[email protected]', 'zeldris', 'zeldris', 'zeldris');
E voilà, a record está inserida na minha tabela:
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.