I'm trying to configure FlyWay to work with two vendors - one (H2) is for local environment, and another one (Mysql) is for ci.
Here's my scripts patch:
My FlyWay bean configuration:
@Bean(initMethod = "migrate")
Flyway flyway() {
Flyway flyway = Flyway
.configure()
.dataSource(dataSource(dataSourceProperties()))
.locations("classpath:db/migration/MySQL", "classpath:db/migration/H2")
.load();
return flyway;
}
@Bean
@Primary
@ConfigurationProperties("spring.datasource")
public DataSourceProperties dataSourceProperties() {
return new DataSourceProperties();
}
@Bean
@ConfigurationProperties("spring.datasource")
public HikariDataSource dataSource(DataSourceProperties properties) {
return properties.initializeDataSourceBuilder().type(HikariDataSource.class)
.build();
}
And my application.yml configuration:
spring:
main:
allow-bean-definition-overriding: true
datasource:
driverClassName: com.mysql.cj.jdbc.Driver
jdbc-url: jdbc:mysql://localhost:3306/messages
username: username
password: password
What I try to achieve is to make flyway run database vendor specific scripts, depending on which database is set in datasource. Here's what I get:
Caused by: org.flywaydb.core.api.FlywayException: Found more than one migration with version 1.1
Offenders:
-> C:\Projects\my-project\out\production\resources\db\specific\MySQL\V1_1__Create_table_message.sql (SQL)
-> C:\Projects\my-project\out\production\resources\db\specific\H2\V1_1__Create_table_message.sql (SQL)
I've already tried to use lowercase vendor names (db/migration/mysql ...) and use db/specific/ instead of db/migration. Nothing worked for me.
The problem is your use of:
.locations("classpath:db/migration/MySQL", "classpath:db/migration/H2")
This will add both migrations to the runtime path. This is what causes the issue, because this configuration instructs flyway to always use the scripts from both locations, instead of only using the H2-scripts for H2 and the MySQL scripts for MySQL.
Instead, you should only add the specific path for the active driver on the path.
Something like
String driverVendor = ..; // something to decide h2 or mysql
Flyway flyway = Flyway
.configure()
.locations("classpath:db/migration/" + driverVendor)
You may need to lowercase the folder names, that is H2
to h2
and MySQL
to mysql
for this to work.
Alternatively, consider using Spring Boots Flyway auto-configuration instead of coding the Flyway configuration in code. This allows you to define the path in the application config as:
spring.flyway.locations=classpath:db/migration/{vendor}
Where {vendor}
will be automatically populated with the vendor name of the driver used to connect.
See also Execute Flyway Database Migrations on Startup
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With