SpringBoot 2 with Flyway: spring.flyway.locations is ignored - java

I am using Spring Boot 2.2.2 with Flyway 5.2.4 and I tried to configure flyway to use a differente location for the scripts, but spring.flyway.locations=filesystem:db_other/migration/{vendor} neither flyway.locations=filesystem:db_other/migration/{vendor} configurations on application.properties worked.
When running the program, the following exception appear in the log:
FlywayMigrationScriptMissingException: Cannot find migration scripts in: [classpath:db/migration]
I already tried using Spring Boot 2.2.1, 2.2.0, 2.1.11 and Flyway 6.1.0 and 6.1.3, but the result is the same.

The default value for that property is classpath:db/migration as shown here (search for flyway).
Since you're using a different folder in the resources directory you should only need to change "filesystem" to "classpath" in your application.properties value.

Actually if was my fault: as I used to work with just spring (not spring boot) I configured my test class with the annotations #ExtendWith(SpringExtension.class) AND #ContextConfiguration(classes = { MyConfiguration.class }) instead of just use #SpringBootTest. When making this change the test worked.

Related

How does spring boot know which property file to use based on environment

I have 4 files in my project:
application.properties
application-dev.properties
application-qa.properties
application-prod.properties
application.properties has a property spring.profiles.active = #active.profile#
When running on local, it uses application-dev.properties file. But in UAT and Prod, it uses respective property files. My question is how does spring boot know to use dev when im running in local and and qa in uat and prod in prod?
What does #active.profile# mean?
This is decided by the "profiles" variable. This is a Set<String>.
The exact way spring detect the profiles depends on the way you run your application.
The most common way is through the System Parameter: -Dspring.profiles.active=dev. So I assume somwhere in your production enviroment this variable gets set.
Alternativelly, if you run your spring app via a builder, you can define the profiles explicitly (code is in kotlin):
SpringApplicationBuilder(MyApp::class.java)
.profiles(*profiles)
.run(*args)
Check this article for more info: https://www.baeldung.com/spring-profiles

Set active Spring Boot profile for Tomcat Webapp internally (via application.properties)

I'd like to use two different spring profiles proda and prodb using Spring Boot 2.0.0 (setting the profile in the application.properties).
In Spring Boot, you can also set the active profile in application.properties, as shown in the following example:
spring.profiles.active=production
Source: 74.6
For now I'm only trying to get proda to work. I've got three different property files:
application-proda.yml
database:
conn:
blablabla: blablaqwer
and
application-prodb.yml
database:
conn:
blablabla: albalbrewq
and also
application.properties
spring.profiles.active=proda
When running the application in the IDE, or packaging it as jar with maven, everything works as expected (active profiles [proda] are set, application-proda.yml is loaded). Calling this in (for example a #PostConstruct of) some class:
System.out.println(Arrays.toString(env.getActiveProfiles()));
will result in
[proda]
but when buildung as war with maven, and deploying it to a Tomcat server, the same code will result in
[]
and application-proda.yml is not loaded. That means the application didn't read the application.properties and therefore didn't load the active profile proda for some reason.
But the finished war has all the needed files under WEB-INF\classes\.
I've seen some solutions where you can set -Dspring.profiles.active=proda as a command line parameter, or set the active profiles in the web.xml, but this is not what I need, as I don't have a web.xml and I'd like to use the Spring Boot feature and declare the profiles in the application.properties. It should work just like in the IDE or packaged as a jar with maven.

Why Spring Boot 2.0 application does not run schema.sql?

While I was using Spring Boot 1.5, on application startup Hibernate executed schema.sql file located in /resources folder when appropriate configuration is set. After Spring Boot 2.0 release this feature does not work any more. I couldn't find anything about this change in documentation.
Here is my application.properties file content:
spring.datasource.url=...
spring.datasource.username=...
spring.datasource.password=...
#spring.jpa.hibernate.ddl-auto=create-drop
spring.jpa.hibernate.ddl-auto=none
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5Dialect
Is there some change in Spring Boot 2.0 or is this an bug/issue?
Check the documents here.
In a JPA-based app, you can choose to let Hibernate create the schema
or use schema.sql, but you cannot do both. Make sure to disable
spring.jpa.hibernate.ddl-auto if you use schema.sql.
You have spring.jpa.hibernate.ddl-auto=create-drop that's why schema.sql is not executed.
Looks like this is the way Spring Boot works.
Edit
I think that the problem(not really a problem) is that your application points to a mysql instance.
See the current Spring Boot properties:
spring.datasource.initialization-mode=embedded # Initialize the datasource with available DDL and DML scripts.
The default value is embedded - e.g. initialize only if you're running and embedded database, like H2.
Also see the answer of Stephan here. He said:
Adding spring.datasource.initialization-mode=always to your project is
enough.
So try to set:
spring.datasource.initialization-mode=always
Not embedded (e.g. MySQL)
If you load a database that is not embedded, in Spring Boot 2 you need to add:
spring.datasource.initialization-mode=always
Check the Migration Guide:
Database Initialization
Basic DataSource initialization is now only enabled for embedded data
sources and will switch off as soon as you’re using a production
database. The new spring.datasource.initialization-mode (replacing
spring.datasource.initialize) offers more control.
Embedded (e.g. h2)
I once had a similar problem, even though it was an h2 (so it was an embedded DB), my h2 configuration was activated by a my-test profile.
My test class was like:
#RunWith(SpringRunner.class)
#SpringBootTest // does not work alone
#ActiveProfiles("my-test")
public class MyEntityRepositoryTest {
The problem is #SpringBootTest alone did not initialize the test database. I had to either use #DataJpaTest or #SpringBootTest+#AutoConfigureTestDatabase. Examples
#RunWith(SpringRunner.class)
#DataJpaTest // works
#ActiveProfiles("sep-test")
public class MyEntityRepositoryTest {
or
#RunWith(SpringRunner.class)
#SpringBootTest // these two
#AutoConfigureTestDatabase // together work
#ActiveProfiles("sep-test")
public class MyEntityRepositoryTest {
Recent Update
As of Spring Boot Version 2.7
the property spring.datasource.initialization-mode has been removed.
You should from this version and onwards use the replacement property spring.sql.init.mode
Example: spring.sql.init.mode:always
Spring Boot 2.7 changelog
It works fine for me, you can try it. Set datasource type to what you like instead of HikariCP.
spring.datasource.initialization-mode=always
spring.datasource.type=com.mysql.jdbc.jdbc2.optional.MysqlDataSource
spring.jpa.hibernate.ddl-auto=none
There have another problem may result data.sql can not be executed,when you don't config the spring.jpa.hibernate.ddl-auto=none,that the data.sql will not be execute d.
I was able to make application run only after excluding Hikary CP like that:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
<exclusions>
<exclusion>
<groupId>com.zaxxer</groupId>
<artifactId>HikariCP</artifactId>
</exclusion>
</exclusions>
</dependency>
Please, see the issue here

Flyway Init Order

I've got a Java Spring Boot application, with Flyway configured as a dependency in my Maven pom.xml (I have a parent pom and a project pom... Flyway is defined in my project pom).
<dependencies>
<dependency>
<groupId>org.flywaydb</groupId>
<artifactId>flyway-core</artifactId>
<version>4.2.0</version>
</dependency>
...
and just a couple of entries in application.properties:
flyway.enabled=true
flyway.out-of-order=true
I can run a maven task to get Flyway to run migrate to create/update my database and then run my application against that, but I'm having trouble getting it to call migrate at the right time just by running my application (which is obviously important in prod). It looks like all of my Spring classes are being instantiated first, some of which involves looking at the database, and then Flyway migration happens after, so for instance if you run the application against an empty database the application crashes when trying to access anything in the database.
Any tips on where to look to see where I'm going wrong to get Flyway to do its migration earlier in the start-up process of my Spring Boot application?
I am not sure how your data source configuration looks like, but you could declare your JPA config in such a way that makes it dependent on the flyway migration.
You could declare a #DependsOn("flyway") annotation on whatever #Config class or datasource bean, "flyway" being the declared name of your flyway configuration bean. Then, on your flyway configuration bean, qualify the bean annotation with an initMethod property like the following: #Bean(initMethod = "migrate").
Try change "flyway.out-of-order=false"
I would suggest you to try using event listners like ApplicationStartedEvent.
#EventListener
public void migrate(ApplicationStartedEvent applicationStartedEvent) {
//do some checks
flyway.migrate();
}

Managing dependencies with spring boot profiles and Gradle

I created a java project that will use spring boot and Gradle. I would like to configure profiles, for the different environment (development on my local machine, systemtest for integration test on server farm machine etc). I would use h2 in memory database for development environment and SqlServer for systemtest environment. In build.gradle I defined the following dependencies
dependencies {
compile("org.springframework.boot:spring-boot-starter-data-jpa")
compile("org.springframework.boot:spring-boot-starter-web-services")
compile('org.springframework.boot:spring-boot-starter-actuator')
runtime('com.h2database:h2:1.4.195')
runtime('com.microsoft.sqlserver:mssql-jdbc')
}
I created a application.yml file, application-development.yml and application-systemtest.yml where I would put common properties and environment specific properties. The file application-systemtest.yml defines the connecction parameters for sql server
spring:
datasource:
url: jdbc:sqlserver://<host>,1433;databaseName=MYDB
username: myuser
password: mypass
driverClassName: com.microsoft.sqlserver.jdbc.SQLServerDriver
jpa:
show-sql: true
hibernate:
dialect: org.hibernate.dialect.SQLServer2012Dialect
I would also create an uber-jar and select the profile as a launch parameter, ie
java -Dspring.profiles.active=systemtest -jar <my uber jar>
The development profiles starts fine and I am running on h2 in memory database. When trying systemtest profile, spring boot fails to load contexts and fails. This is caused by spring boot finding h2 dependency and trying to configure datasource defined in application-systemtest.yml
So I modified the build.gradle dependencies closure
def profile = project.findProperty('spring.profiles.active')
dependencies {
compile("org.springframework.boot:spring-boot-starter-data-jpa")
compile("org.springframework.boot:spring-boot-starter-web-services")
compile('org.springframework.boot:spring-boot-starter-actuator')
if (profile == 'development') {
runtime('com.h2database:h2:1.4.195')
} else {
runtime('com.microsoft.sqlserver:mssql-jdbc')
}
}
This time spring boot start correctly. Don't like very much this solution as I have to handle the profile configuration partly with Gradle. I would like to know if there is a way to configure spring boot so that profile is completely managed within itself, resolving h2 in development environment and sqlserver in systemtest environment, leaving Gradle unaware of spring profiles.
How to solve this problem ?
It wouldn't be advisable to have a different artifact / binary depending on the DB product. Try to configure the datasources / Spring profiles as suggested by #M. Deinum to prevent the datasource to be configured as H2 when using a different DB.

Categories

Resources