'Spring Boot: run liquibase migrations without starting app
In Spring Boot, the documentation seems to encourage running migrations on app startup.
This is fine, but sometimes app startup may have side effects / dependencies that I don't want to bother with - I just want to run the migrations on their own. Think just setting up a local dev database, to poke around in it, without even running the app.
In Dropwizard by comparison, running migrations alone is straightforward with built in arguments for the app, like so
java -jar hello-world.jar db migrate helloworld.yml
Is there anything equivalent for Spring Boot? Or do I just have to drop down and run liquibase directly?
I'm interested in a direct answer, but also kind of interested in seeing if I'm misunderstanding something at a higher level - like perhaps this approach of running on startup is generally 'better' for some reasons I haven't discovered yet, so you're encouraged solely to do it this way by Spring Boot as a design choice.
Solution 1:[1]
I know this is an old question, but in case someone else stumbles upon it, this might be useful.
You can define a command line argument for your app, that you will use to only spin up a portion of the app context that will run migration.
Here's an example in Kotlin:
import org.springframework.boot.ApplicationContextFactory.ofContextClass
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration
import org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration
import org.springframework.boot.builder.SpringApplicationBuilder
import org.springframework.boot.runApplication
import org.springframework.context.annotation.AnnotationConfigApplicationContext
import org.springframework.context.annotation.Import
@SpringBootApplication
class Application
@Import(DataSourceAutoConfiguration::class, LiquibaseAutoConfiguration::class)
class LiquibaseInit
fun main(args: Array<String>) {
if (args.contains("dbinit")) {
SpringApplicationBuilder(LiquibaseInit::class.java)
.contextFactory(ofContextClass(AnnotationConfigApplicationContext::class.java))
.run(*args)
return
}
runApplication<Application>(*args)
}
Note: with Spring Boot 2.4.0 and earlier use SpringApplicationBuilder#contextClass
instead of contextFactory
.
We have 2 classes declared here: Application
(the main app class having @SpringBootApplication
annotation) and LiquiBaseInit
(having @DataSourceAutoConfiguration
and @LiquibaseAutoConfiguration
), the first one will spin up the whole context, while the latter will only spin up the beans necessary for Liquibase to run migration.
Inside the main function we check if the arguments array has a string dbinit
and if it is there we start an application context out of LiquiBaseInit
class.
Now you can run migration with your jar file like this:
java -jar hello-world.jar dbinit
If you're going to run your app in Kubernetes, you might also want to check out this article in my blog: https://blog.monosoul.dev/2021/12/26/using-liquibase-with-kubernetes/ .
Solution 2:[2]
This answer mentions a hook that runs after Liquibase. In that question, it was used to populate the database, probably with test or default values.
@Bean
@DependsOn("liquibase")
public YourBean yourBean() {
return new YourBean();
}
static class YourBean {
@PostConstruct
public void shutdown() {
// Exit your application here.
);
}
}
That could work. I don't know, you'd probably even have access to the liquibase mode and only shut down when it was "create."
Solution 3:[3]
You can use different Spring profiles: For instance, use a profile called 'init' which will activate the 'liquibase' profile.
application.yml: (disable Liquibase by default)
spring:
liquibase:
enabled: false
application-init.yml: (does not run a web container, so spring will close automatically after startup)
spring:
profiles:
include: liquibase
main:
web-application-type: none
spring-liquibase.yml: (enables liquibase)
spring:
liquibase:
enabled: true
change-log: classpath:/db/changelog/changelog.xml
This setup allows you to run Liquibase as an init container (spring.profiles.active=init), but if you want to you can still run Liquibase as part of your web-app (spring.profiles.active=liquibase).
Solution 4:[4]
In general, it might be just less work to run migrations on app start, especially if you're using Spring Boot and its all set up for you. You can then just stop the app.
However if you really would like to run migrations without the Spring Boot app, you can use the Liquibase Gradle and Maven plugins: https://github.com/liquibase/liquibase-gradle-plugin https://docs.liquibase.com/tools-integrations/maven/home.html
This will require you to set up the database credentials in another config file, in addition to your application config, so that the plugins can connect to the database.
Solution 5:[5]
For this purpose we created our own script that allows not only to gen migrations but also to manually apply them, however it could be applied only from gradle, see: https://github.com/Wissance/SpringUu
to apply update we use following command:
.\gradlew.bat update -PrunList='changesApply'
to specify db connection edit gradle section changesApply
For more details about our tool see article:
https://m-ushakov.medium.com/code-first-with-spring-boot-hibernate-and-liquibase-48f5c9998d95
Solution 6:[6]
U can set up and configure maven liquibase plugin: https://docs.liquibase.com/tools-integrations/maven/commands/home.html
It allows to use migrations without starting spring boot app itself
can be set up as part of building artifact or like separate task
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | |
Solution 2 | knallfrosch |
Solution 3 | blagerweij |
Solution 4 | Michael |
Solution 5 | Michael Ushakov |
Solution 6 | Oleg Maksymuk |