Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Setup LiquiBase in a Gradle Spring Boot Hibernate project

I'm having a hard time setting up LiquiBase in my Spring Boot project. I tried looking through the docs and finding some guides - but they seem contradict each other :(

I wish to use LiquiBase via Gradle and I want it to generate the changelogs from Hibernate and end up with a SQL script I can run on the server to update the schema to the appropriate version.

To get it to run via Gradle I'm using this plugin https://github.com/liquibase/liquibase-gradle-plugin using the recommended setup shown in their README.

To get the Hibernate diff to work I'm using https://github.com/liquibase/liquibase-hibernate

Here's my build.gradle file:

buildscript {
    ext {
        springBootVersion = '2.0.5.RELEASE'
    }
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
    }
}

plugins {
    id 'java'
    id 'net.ltgt.apt' version '0.10' // https://projectlombok.org/setup/gradle
    id 'org.liquibase.gradle' version '2.0.1' // https://github.com/liquibase/liquibase-gradle-plugin
}

apply plugin: 'eclipse-wtp'
apply plugin: 'org.springframework.boot'
apply plugin: 'io.spring.dependency-management'
apply plugin: 'war'

group = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = 1.8

repositories {
    mavenCentral()

    maven {
        credentials {
            username = oracleUser
            password = oraclePass
        }
        url 'https://www.oracle.com/content/secure/maven/content'
    }
}

liquibase {
  activities {
    main {
      changeLogFile 'main.groovy'
      url 'jdbc:oracle:thin:@localhost:1521:XE'
      referenceUrl 'hibernate:spring:com.example?dialect=org.hibernate.dialect.Oracle10gDialect'
      username 'user'
      password 'pass'
    }
  }
}

configurations {
    providedRuntime
}

dependencies {
    compile('org.springframework.boot:spring-boot-starter-data-jpa')
    compile('org.springframework.boot:spring-boot-starter-data-rest')
    compile('org.springframework.boot:spring-boot-starter-hateoas')
    compile('org.springframework.boot:spring-boot-starter-jooq')
    compile('org.springframework.boot:spring-boot-starter-web')
    compile('org.springframework.boot:spring-boot-starter-mail')
    compile('com.github.waffle:waffle-spring-boot-starter:1.9.0')
    compile('com.oracle.jdbc:ojdbc8:12.2.0.1')
    runtime('org.springframework.boot:spring-boot-devtools')
    compileOnly('org.projectlombok:lombok')
    apt('org.projectlombok:lombok:1.18.2')
    liquibaseRuntime('org.liquibase:liquibase-core:3.6.2')
    liquibaseRuntime('org.liquibase:liquibase-groovy-dsl:2.0.1')
    liquibaseRuntime('org.liquibase.ext:liquibase-hibernate5:3.6')
    liquibaseRuntime('com.oracle.jdbc:ojdbc8:12.2.0.1') // duplicate...
    providedRuntime('org.springframework.boot:spring-boot-starter-tomcat')
    testCompile('org.springframework.boot:spring-boot-starter-test')
    testCompile('org.springframework.restdocs:spring-restdocs-mockmvc')
}

Running it via

> .\gradlew diffChangeLog -PrunList=main

But fails with

Task :diffChangeLog liquibase-plugin: Running the 'main' activity... Starting Liquibase at Wed, 26 Sep 2018 13:36:24 CEST (version 3.6.2 built at 2018-07-03 11:28:09) Exception in thread "main" java.lang.NoClassDefFoundError: org/springframework/core/io/ClassPathResource at liquibase.ext.hibernate.database.HibernateSpringPackageDatabase.isXmlFile(HibernateSpringPackageDatabase.java:54)

It looks like it cannot find Spring Boot. So I then tried removing the liquibaseRuntime but then the LiquiBase Gradle plugin complains that liquibaseRuntime is missing.

Seems I'm stuck in a loop. What is a sane way of setting this up? I really don't want to repeat every dependency inside the liquibaseRuntime. Also the doc literally says:

dependencies {
  // All of your normal project dependencies would be here in addition to...
  liquibaseRuntime 'org.liquibase:liquibase-core:3.6.1'
  liquibaseRuntime 'org.liquibase:liquibase-groovy-dsl:2.0.1'
  liquibaseRuntime 'mysql:mysql-connector-java:5.1.34'
}

Note the

// All of your normal project dependencies would be here in addition to...

So yeah. Why...

Please help!

Also... I noticed that you have to write database config twice. Why is that needed when it's already set in spring boot config?


PROGRESS

So changing liquibaseRuntime to

liquibaseRuntime('org.liquibase:liquibase-core:3.6.2')
liquibaseRuntime('org.liquibase:liquibase-groovy-dsl:2.0.1')
liquibaseRuntime('org.liquibase.ext:liquibase-hibernate5:3.6')
liquibaseRuntime('com.oracle.jdbc:ojdbc8:12.2.0.1')
liquibaseRuntime('org.springframework.boot:spring-boot-starter-data-jpa')
liquibaseRuntime files('src/main')

Makes the errors go away. But it still doesn't work.

Running this command

.\gradlew diff

Gives me this output

> Task :diff
liquibase-plugin: Running the 'main' activity...
Starting Liquibase at Wed, 26 Sep 2018 16:47:19 CEST (version 3.6.2 built at 2018-07-03 11:28:09)

Diff Results:
Reference Database: null @ hibernate:spring:com.example.model?dialect=org.hibernate.dialect.Oracle10gDialect (Default Schema: HIBERNATE)
Comparison Database: SYSTEM @ jdbc:oracle:thin:@localhost:1521:XE (Default Schema: SYSTEM)
Compared Schemas: HIBERNATE -> SYSTEM
Product Name:
     Reference:   'Hibernate'
     Target: 'Oracle'
Product Version:
     Reference:   '5.2.17.Final'
     Target: 'Oracle Database 11g Express Edition Release 11.2.0.2.0 - 64bit Production'
Missing Catalog(s):
     HIBERNATE
Unexpected Catalog(s): NONE
Changed Catalog(s): NONE
Missing Column(s): NONE
Unexpected Column(s): NONE
Changed Column(s): NONE
Missing Foreign Key(s): NONE
Unexpected Foreign Key(s): NONE
Changed Foreign Key(s): NONE
Missing Index(s): NONE
Unexpected Index(s): NONE
Changed Index(s): NONE
Missing Primary Key(s): NONE
Unexpected Primary Key(s): NONE
Changed Primary Key(s): NONE
Missing Sequence(s): NONE
Unexpected Sequence(s): NONE
Changed Sequence(s): NONE
Missing Stored Procedure(s): NONE
Unexpected Stored Procedure(s): NONE
Changed Stored Procedure(s): NONE
Missing Table(s): NONE
Unexpected Table(s): NONE
Changed Table(s): NONE
Missing Unique Constraint(s): NONE
Unexpected Unique Constraint(s): NONE
Changed Unique Constraint(s): NONE
Missing View(s): NONE
Unexpected View(s): NONE
Changed View(s): NONE
Liquibase command 'diff' was executed successfully.


BUILD SUCCESSFUL in 7s
1 actionable task: 1 executed

When running against an empty database. So yeah - it doesn't work :(

like image 552
Snæbjørn Avatar asked Sep 26 '18 11:09

Snæbjørn


People also ask

Does Liquibase use hibernate?

Hibernate can be used with several databases that are supported by Liquibase, such as H2. To use an H2 database with Liquibase, you must have the H2 JDBC driver JAR file., which is pre-installed with Liquibase.

How do you integrate Liquibase?

Integrating Liquibase into your Spring Boot application is extremely easy. You just have to add the Liquibase Core to your classpath. That's all you need to do. The Liquibase integration will automatically load the master changelog file from the db changelog directory.


1 Answers

I know this is an old thread, but I wanted to add some clarification for those who find this answer later...

The liquibaseRuntime configuration does not inherit from any other configuration. This is because in most cases, Liquibase only needs to be able to parse the change logs and connect to the database. To use something like the Hibernate module, or to generate change logs from your code, you need to add extra things to the liquibaseRuntime, such as Hibernate or Spring Data, and you'd need srcSets.main.output to be able to find your project files themselves.

The comment that said "All of your normal project dependencies would be here in addition to..." referred to the fact that you would have a bunch of other dependencies in the block to build and run your project, not that they would be part of the liquibaseRuntime configuration. If you do want all of the libraries from your project to also be part of the liquibaseRuntime, you can add configurations.liquibaseRuntime.extendsFrom configurations.runtime you your build.gradle, or if you already have a configurations block, you can add liquibaseRuntime.extendsFrom runtime to that block. This should add all the project dependencies, and the project files themselves, to your liquibaseRuntime.

I hope this helps.

like image 184
Steve Saliman Avatar answered Sep 22 '22 13:09

Steve Saliman