I have an existing spring boot project and a database for the same. Now, I would like to add liquibase to handle further database migration. What are the correct steps to do this?
I have followed this article to add liquibase and generate changelog. Most articles I've found talk about using liquibase in a project starting from scratch or are not too detailed about the implementation. So far, I've done the following:
Added the dependencies and plugin in pom.xml
<dependencies>
//..other dependencies
<dependency>
<groupId>org.liquibase</groupId>
<artifactId>liquibase-core</artifactId>
</dependency>
<dependency>
<groupId>org.liquibase</groupId>
<artifactId>liquibase-maven-plugin</artifactId>
<version>3.6.2</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.liquibase</groupId>
<artifactId>liquibase-maven-plugin</artifactId>
<version>3.6.2</version>
<configuration>
<propertyFile>src/main/resources/liquibase.properties</propertyFile>
</configuration>
</plugin>
</plugins>
</build>
Added the liquibase.properties file under src/main/resources
url=jdbc:mysql://localhost:3306/demodb
username=root
password=root
driver=com.mysql.jdbc.Driver
outputChangeLogFile=src/main/resources/db/changelog/changes/demodb-changelog.xml
Updated the application.properties file under src/main/resources to handle changelogs
#Hibernate
spring.datasource.url=jdbc:mysql://localhost:3306/demodb
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.username=root
spring.datasource.password=root
#Jpa
spring.jpa.hibernate.ddl-auto=none
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL5Dialect
#Liquibase
spring.liquibase.change-log=classpath:db/changelog/db.changelog-master.xml
Created the db.changelog-master.xml
file under src/main/resources/db/changelog
<?xml version="1.0" encoding="UTF-8"?>
<databaseChangeLog
xmlns="http://www.liquibase.org/xml/ns/dbchangelog/1.9"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation = "http://www.liquibase.org/xml/ns/dbchangelog/1.9
http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-1.9.xsd">
</databaseChangeLog>
Ran the spring boot app so that two new tables are created in the database - DATABASECHANGELOG
(which is empty at the moment) and DATABASECHANGELOGLOCK
(which has a single null entry at the moment)
Generated the demodb-changelog.xml
file from the terminal to create the changelog for the current state of the database
mvn liquibase:generateChangeLog
Then to sync the current changelogs as executed, in liquibase.properties
added:
changeLogFile=src/main/resources/db/changelog/changes/demodb-changelog.xml
And then from the terminal ran:
mvn liquibase:changelogSync
Now, the DATABASECHANGELOG
table has entries for the changelogs as executed.
Next in the db.changelog-master.xml
file, added the generated file:
<include file="db/changelog/changes/demodb-changelog.xml"/>
Now, when I run the app, I get the exception:
Caused by: liquibase.exception.MigrationFailedException:
Migration failed for change set db/changelog/changes/demodb-changelog.xml
Reason: liquibase.exception.DatabaseException: Table 'abc' already exists
So, this is trying to run the changelog files again. How do I configure to run only those changesets that have not yet been run? I thought that the function of the DATABASECHANGELOG
was to handle the changesets that have been executed, but I guess I'm wrong here.
I could run the application without the include
tag in db.changelog-master.xml
, but I guess all the changelog files need to be listed here as I would need all the changelog files if I were to run this app in a different machine to create the entire database from scratch.
So how to configure liquibase to run only changelogs that have not yet been executed?