10

I have a spring boot application and I want to add liquibase configuration change log for it.

I have created a LiquibaseConfig class for configuring liquibase:

@Configuration
public class LiquibaseConfiguration {

    @Value("${com.foo.bar.liquibase.changelog}")
    private String changelog;

    @Autowired
    MysqlDataSource dataSource;

    @Bean
    public SpringLiquibase liquibase()  {
        SpringLiquibase liquibase = new SpringLiquibase();
        liquibase.setDataSource(dataSource);
        liquibase.setChangeLog(changelog);
        return liquibase;
    }

}

and I have configured the datasource information in properties file:

spring.datasource.url=jdbc:mysql://localhost:3306/dms
spring.datasource.username=root
spring.datasource.password=test
spring.datasource.testWhileIdle = true
spring.jpa.show-sql = true

#liquibase
com.foo.bar.liquibase.changelog=classpath:/db/changelog/db.changelog.xml

when I run my application I receive this error:

org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'liquibaseConfiguration': Unsatisfied dependency expressed through field 'dataSource': No qualifying bean of type [com.mysql.jdbc.jdbc2.optional.MysqlDataSource] found for dependency [com.mysql.jdbc.jdbc2.optional.MysqlDataSource]: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.mysql.jdbc.jdbc2.optional.MysqlDataSource] found for dependency [com.mysql.jdbc.jdbc2.optional.MysqlDataSource]: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}

Now I understood that this means the application cannot autowire the MysqlDataSource dataSource; but I need to pass the data source to liquibase bean. How can I do that?

Muhammad Bekette
  • 1,396
  • 1
  • 24
  • 60

3 Answers3

15

Here's a simple step to integrate liquibase in spring boot

STEP 1

Add liquibase dependency

Gradle

runtime "org.liquibase:liquibase-core"

Maven

<dependency>
    <groupId>org.liquibase</groupId>
    <artifactId>liquibase-core</artifactId>
    <scope>runtime</scope>
</dependency>

STEP 2

Add liquibase changelog file path in application.yml

liquibase:
  enabled: true #this is optional as enabled by default
  change-log: classpath:/liquibase/db-changelog.xml

Notice property liquibase.change-log. I'm referring path as /liquibase/db-changelog.xml. so you should have a file name db-changelog.xml inside src/main/resources/liquibase/

STEP 3

Add your changesets on the file and when Spring-Boot application is started (spring-boot:run) your changeset will be loaded.

This will use default dataSource that your app uses.

More Info: http://docs.spring.io/spring-boot/docs/1.4.3.RELEASE/reference/htmlsingle/#howto-execute-liquibase-database-migrations-on-startup

Update

For Spring Boot 2.0 as @veben pointed out in comment use

spring:
    liquibase:
        change-log: #path
A0__oN
  • 8,740
  • 6
  • 40
  • 61
  • 3
    You're basically right, this should work out-of-the box with auto-configuration (and less boilerplate code) in the simplest case. The changelog should be applied to the primary dataSource (I assume he only has one), but with multiple sources you might want to instantiate a SpringLiquibase bean with custom initialization yourself... – DoNuT Apr 05 '17 at 12:04
  • 2
    Notice that with Spring boot 2, the properties is no more "liquibase.change-log" but "spring.liquibase.change-log" – veben Nov 16 '18 at 14:04
1

Rather than autowire the datasource, create a method in your Liquibase Configuration Object to create the datasource.

private DataSource dataSource() {
    DriverManagerDataSource dataSource = new DriverManagerDataSource();
    dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
    dataSource.setUsername("user");
    dataSource.setPassword("pswd");
    dataSource.setUrl("jdbc:mysql://127.0.0.1:3306/db");
    dataSource.setSchema("dbName");
    return dataSource;
}

then in your bean generation method

liquibase.setDataSource(dataSource());

This gives you a chance to specify the database parameters on the fly, I still had the changelog location in the applications.properties file along with the enablement of liquibase. I've tried it, and it works for me.

0

I had a similar construct for my application, have you tried injecting a more generic javax.sql.DataSource instead?

My guess is that Spring uses the non-specific type for this bean, on top of that you shouldn't even use a database-specific type if your application could be configured to use a totally different source, i.e. by just changing the datasource URL in the configuration file.

DoNuT
  • 463
  • 1
  • 7
  • 23