Baeldung Pro – NPI EA (cat = Baeldung)
announcement - icon

Baeldung Pro comes with both absolutely No-Ads as well as finally with Dark Mode, for a clean learning experience:

>> Explore a clean Baeldung

Once the early-adopter seats are all used, the price will go up and stay at $33/year.

Partner – Microsoft – NPI EA (cat = Baeldung)
announcement - icon

Azure Container Apps is a fully managed serverless container service that enables you to build and deploy modern, cloud-native Java applications and microservices at scale. It offers a simplified developer experience while providing the flexibility and portability of containers.

Of course, Azure Container Apps has really solid support for our ecosystem, from a number of build options, managed Java components, native metrics, dynamic logger, and quite a bit more.

To learn more about Java features on Azure Container Apps, visit the documentation page.

You can also ask questions and leave feedback on the Azure Container Apps GitHub page.

Partner – Microsoft – NPI EA (cat= Spring Boot)
announcement - icon

Azure Container Apps is a fully managed serverless container service that enables you to build and deploy modern, cloud-native Java applications and microservices at scale. It offers a simplified developer experience while providing the flexibility and portability of containers.

Of course, Azure Container Apps has really solid support for our ecosystem, from a number of build options, managed Java components, native metrics, dynamic logger, and quite a bit more.

To learn more about Java features on Azure Container Apps, you can get started over on the documentation page.

And, you can also ask questions and leave feedback on the Azure Container Apps GitHub page.

Partner – Orkes – NPI EA (cat=Spring)
announcement - icon

Modern software architecture is often broken. Slow delivery leads to missed opportunities, innovation is stalled due to architectural complexities, and engineering resources are exceedingly expensive.

Orkes is the leading workflow orchestration platform built to enable teams to transform the way they develop, connect, and deploy applications, microservices, AI agents, and more.

With Orkes Conductor managed through Orkes Cloud, developers can focus on building mission critical applications without worrying about infrastructure maintenance to meet goals and, simply put, taking new products live faster and reducing total cost of ownership.

Try a 14-Day Free Trial of Orkes Conductor today.

Partner – Orkes – NPI EA (tag=Microservices)
announcement - icon

Modern software architecture is often broken. Slow delivery leads to missed opportunities, innovation is stalled due to architectural complexities, and engineering resources are exceedingly expensive.

Orkes is the leading workflow orchestration platform built to enable teams to transform the way they develop, connect, and deploy applications, microservices, AI agents, and more.

With Orkes Conductor managed through Orkes Cloud, developers can focus on building mission critical applications without worrying about infrastructure maintenance to meet goals and, simply put, taking new products live faster and reducing total cost of ownership.

Try a 14-Day Free Trial of Orkes Conductor today.

eBook – Guide Spring Cloud – NPI EA (cat=Spring Cloud)
announcement - icon

Let's get started with a Microservice Architecture with Spring Cloud:

>> Join Pro and download the eBook

eBook – Mockito – NPI EA (tag = Mockito)
announcement - icon

Mocking is an essential part of unit testing, and the Mockito library makes it easy to write clean and intuitive unit tests for your Java code.

Get started with mocking and improve your application tests using our Mockito guide:

Download the eBook

eBook – Java Concurrency – NPI EA (cat=Java Concurrency)
announcement - icon

Handling concurrency in an application can be a tricky process with many potential pitfalls. A solid grasp of the fundamentals will go a long way to help minimize these issues.

Get started with understanding multi-threaded applications with our Java Concurrency guide:

>> Download the eBook

eBook – Reactive – NPI EA (cat=Reactive)
announcement - icon

Spring 5 added support for reactive programming with the Spring WebFlux module, which has been improved upon ever since. Get started with the Reactor project basics and reactive programming in Spring Boot:

>> Join Pro and download the eBook

eBook – Java Streams – NPI EA (cat=Java Streams)
announcement - icon

Since its introduction in Java 8, the Stream API has become a staple of Java development. The basic operations like iterating, filtering, mapping sequences of elements are deceptively simple to use.

But these can also be overused and fall into some common pitfalls.

To get a better understanding on how Streams work and how to combine them with other language features, check out our guide to Java Streams:

>> Join Pro and download the eBook

eBook – Jackson – NPI EA (cat=Jackson)
announcement - icon

Do JSON right with Jackson

Download the E-book

eBook – HTTP Client – NPI EA (cat=Http Client-Side)
announcement - icon

Get the most out of the Apache HTTP Client

Download the E-book

eBook – Maven – NPI EA (cat = Maven)
announcement - icon

Get Started with Apache Maven:

Download the E-book

eBook – Persistence – NPI EA (cat=Persistence)
announcement - icon

Working on getting your persistence layer right with Spring?

Explore the eBook

eBook – RwS – NPI EA (cat=Spring MVC)
announcement - icon

Building a REST API with Spring?

Download the E-book

Course – LS – NPI EA (cat=Jackson)
announcement - icon

Get started with Spring and Spring Boot, through the Learn Spring course:

>> LEARN SPRING
Course – RWSB – NPI EA (cat=REST)
announcement - icon

Explore Spring Boot 3 and Spring 6 in-depth through building a full REST API with the framework:

>> The New “REST With Spring Boot”

Course – LSS – NPI EA (cat=Spring Security)
announcement - icon

Yes, Spring Security can be complex, from the more advanced functionality within the Core to the deep OAuth support in the framework.

I built the security material as two full courses - Core and OAuth, to get practical with these more complex scenarios. We explore when and how to use each feature and code through it on the backing project.

You can explore the course here:

>> Learn Spring Security

Course – All Access – NPI EA (cat= Spring)
announcement - icon

All Access is finally out, with all of my Spring courses. Learn JUnit is out as well, and Learn Maven is coming fast. And, of course, quite a bit more affordable. Finally.

>> GET THE COURSE
Course – LSD – NPI EA (tag=Spring Data JPA)
announcement - icon

Spring Data JPA is a great way to handle the complexity of JPA with the powerful simplicity of Spring Boot.

Get started with Spring Data JPA through the guided reference course:

>> CHECK OUT THE COURSE

Partner – LambdaTest – NPI EA (cat=Testing)
announcement - icon

End-to-end testing is a very useful method to make sure that your application works as intended. This highlights issues in the overall functionality of the software, that the unit and integration test stages may miss.

Playwright is an easy-to-use, but powerful tool that automates end-to-end testing, and supports all modern browsers and platforms.

When coupled with LambdaTest (an AI-powered cloud-based test execution platform) it can be further scaled to run the Playwright scripts in parallel across 3000+ browser and device combinations:

>> Automated End-to-End Testing With Playwright

Course – Spring Sale 2025 – NPI EA (cat= Baeldung)
announcement - icon

Yes, we're now running our Spring Sale. All Courses are 25% off until 26th May, 2025:

>> EXPLORE ACCESS NOW

Course – Spring Sale 2025 – NPI (cat=Baeldung)
announcement - icon

Yes, we're now running our Spring Sale. All Courses are 25% off until 26th May, 2025:

>> EXPLORE ACCESS NOW

1. Overview

In this quick tutorial, we’ll learn how to use Liquibase to evolve the database schema of a Java web application. First, we’ll examine a general Java app, and then we’ll focus on some interesting options available that integrate well with Spring and Hibernate.

When using Liquibase, we can describe the evolution of the database schema using a sequence of changelog files. Although these files can be written in many formats, such as SQL, XML, JSON, and YAML, here we’ll focus only on the XML format to describe changes for our DB. So, we can have many changelog files for our DB as we change its schema over time. Additionally, all these files have a reference in a single root changelog file named master.xml, which Liquibase will use.

We can use the include and includeAll attributes to nest other changelog files under this root changelog.

Let’s start by including the latest liquibase-core dependency in our pom.xml:

<dependency>
    <groupId>org.liquibase</groupId>
    <artifactId>liquibase-core</artifactId>
    <version>4.27.0</version>
</dependency>

Further reading:

Introduction to Liquibase Rollback

Learn how to use the rollback feature of a Liquibase framework.

Database Migrations with Flyway

This article describes key concepts of Flyway and how we can use this framework to continuously remodel our application's database schema reliably and easily.

Quick Guide on Loading Initial Data with Spring Boot

A quick and practical example of using data.sql and schema.sql files in Spring Boot.

2. The Database Change Log

First, let’s take a look at a simple XML changelog file to understand its structure. For this example, we created a file named 20170503041524_added_entity_Car.xml, which adds a new table called car with id, make, brand, and price as its column:

<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-latest.xsd">
   ...
   <!--Added the entity Car-->
   <changeSet id="20170503041524-1" author="user">
      <createTable tableName="car">
         <column name="id" type="bigint" autoIncrement="${autoIncrement}">
            <constraints primaryKey="true" nullable="false" />
         </column>
         <column name="make" type="varchar(255)">
            <constraints nullable="true" />
         </column>
         <column name="brand" type="varchar(255)">
            <constraints nullable="true" />
         </column>
         <column name="price" type="double">
            <constraints nullable="true" />
         </column>
      </createTable>
   </changeSet>
</databaseChangeLog>

Let’s ignore all the namespace definitions for a second and focus on the changeSet tag. It’s worth noting how an id and author attributes identify the change set. This ensures that any given change is applied only once. Moreover, we can see directly the author of the change as well.

Now, to use this change log, we need to define that file in the master.xml:

<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-latest.xsd">
   
    <include file="classpath:config/liquibase/changelog/00000000000000_initial_schema.xml" relativeToChangelogFile="false" />
   
    <include file="classpath:config/liquibase/changelog/20170503041524_added_entity_Car.xml" relativeToChangelogFile="false" />

</databaseChangeLog>

Now, Liquibase uses the master.xml file to track the changesets that have already been applied to the database. To reduce conflicts, we prepend the file containing the changeset with a data timestamp. The date timestamp allows Liquibase to determine which changesets have already been applied and which still need to be applied. This is just a convention we use and can be changed according to our needs. 

Once the changesets are applied, we cannot normally edit the same ones further. So, for any given schema modification, we must create a new changeset file, which will provide consistency in our database versioning.

Let’s now see how to wire this into our Spring application and make sure that it runs when the application starts up.

3. Run Liquibase With a Spring Bean

Our first option to run the changes on application startup is via a Spring bean.

There are, of course, many other ways, but this is a good, simple way to go if we’re dealing with a Spring application:

@Bean
public SpringLiquibase liquibase() {
    SpringLiquibase liquibase = new SpringLiquibase();
    liquibase.setChangeLog("classpath:config/liquibase/master.xml");
    liquibase.setDataSource(dataSource());
    return liquibase;
}

Alternatively, a more complete configuration file requires additional settings:

@Bean
public SpringLiquibase liquibase(@Qualifier("taskExecutor") TaskExecutor taskExecutor,
        DataSource dataSource, LiquibaseProperties liquibaseProperties) {

    // Use liquibase.integration.spring.SpringLiquibase if you don't want Liquibase to start asynchronously
    SpringLiquibase liquibase = new AsyncSpringLiquibase(taskExecutor, env);
    liquibase.setDataSource(dataSource);
    liquibase.setChangeLog("classpath:config/liquibase/master.xml");
    liquibase.setContexts(liquibaseProperties.getContexts());
    liquibase.setDefaultSchema(liquibaseProperties.getDefaultSchema());
    liquibase.setDropFirst(liquibaseProperties.isDropFirst());
    if (env.acceptsProfiles(JHipsterConstants.SPRING_PROFILE_NO_LIQUIBASE)) {
        liquibase.setShouldRun(false);
    } else {
        liquibase.setShouldRun(liquibaseProperties.isEnabled());
        log.debug("Configuring Liquibase");
    }
    return liquibase;
}

Again, we create our master.xml file on the project’s classpath. Therefore, if the location differs, we might want to provide the correct path.

4. Use Liquibase With Spring Boot

When using Spring Boot, we don’t need to define a bean for Liquibase, as including the liquibase-core dependency will do that for us. But we need to put the master.xml specifically in src/main/resources/config/liquibase/master.xml so that Liquibase can read it and run automatically on startup.

Alternatively, we can also change the default changelog file location by setting the spring.liquibase.change-log property:

spring.liquibase.change-log=classpath:liquibase-changeLog.xml

5. Disable Liquibase in Spring Boot

Sometimes, we might not want to run Liquibase migration on startup. So, to disable Liquibase, we can use spring.liquibase.enabled property:

spring.liquibase.enabled=false

This way, Liquibase configurations are not applied, and the schema of the database stays the same.

We should keep in mind that applications before Spring Boot 2.x, required the use of liquibase.enabled property:

liquibase.enabled=false

6. Generate the changelog With a Maven Plugin

Writing changelog files manually can be time-consuming and error-prone. Instead, we can use the Liquibase Maven plugin to generate one from an existing database and save ourselves a lot of work.

6.1. Plugin Configuration

Let’s use the latest liquibase-maven-plugin dependency in our pom.xml:

<plugin>
   <groupId>org.liquibase</groupId>
   <artifactId>liquibase-maven-plugin</artifactId>
   <version>4.27.0</version>
    ...
   <configuration>
      ...
      <driver>org.h2.Driver</driver>
      <url>jdbc:h2:file:./target/h2db/db/carapp</url>
      <username>carapp</username>
      <password />
      <outputChangeLogFile>src/main/resources/liquibase-outputChangeLog.xml</outputChangeLogFile>
   </configuration>
</plugin>

Above, we are just describing the database driver with its related configurations and the output of the change log file.

6.2. Generate a Changelog From an Existing Database

Let’s use a mvn command to generate a changelog from an existing database:

mvn liquibase:generateChangeLog

Now, we can use the resulting changelog file to either create an initial DB schema or to populate data.

This will create a changeLog file in the configured location:

<databaseChangeLog ...>
   <changeSet id="00000000000001" author="jhipster">
      <createTable tableName="jhi_persistent_audit_event">
         <column name="event_id" type="bigint" autoIncrement="${autoIncrement}">
            <constraints primaryKey="true" nullable="false" />
         </column>
         <column name="principal" type="varchar(50)">
            <constraints nullable="false" />
         </column>
         <column name="event_date" type="timestamp" />
         <column name="event_type" type="varchar(255)" />
      </createTable>
      <createTable tableName="jhi_persistent_audit_evt_data">
         <column name="event_id" type="bigint">
            <constraints nullable="false" />
         </column>
         <column name="name" type="varchar(150)">
            <constraints nullable="false" />
         </column>
         <column name="value" type="varchar(255)" />
      </createTable>
      <addPrimaryKey columnNames="event_id, name" tableName="jhi_persistent_audit_evt_data" />
      <createIndex indexName="idx_persistent_audit_event" tableName="jhi_persistent_audit_event" unique="false">
         <column name="principal" type="varchar(50)" />
         <column name="event_date" type="timestamp" />
      </createIndex>
      <createIndex indexName="idx_persistent_audit_evt_data" tableName="jhi_persistent_audit_evt_data" unique="false">
         <column name="event_id" type="bigint" />
      </createIndex>
      <addForeignKeyConstraint baseColumnNames="event_id" baseTableName="jhi_persistent_audit_evt_data" constraintName="fk_evt_pers_audit_evt_data" referencedColumnNames="event_id" referencedTableName="jhi_persistent_audit_event" />
   </changeSet>

   <changeSet id="20170503041524-1" author="jhipster">
      <createTable tableName="car">
         <column name="id" type="bigint" autoIncrement="${autoIncrement}">
            <constraints primaryKey="true" nullable="false" />
         </column>
         <column name="make" type="varchar(255)">
            <constraints nullable="true" />
         </column>
         <column name="brand" type="varchar(255)">
            <constraints nullable="true" />
         </column>
         <column name="price" type="double">
            <constraints nullable="true" />
         </column>
         <!-- jhipster-needle-liquibase-add-column - JHipster will add columns here, do not remove-->
      </createTable>
   </changeSet>
</databaseChangeLog>

6.3. Generate a ChangeLog From Diffs Between Two Databases

Next, using the diff command, we can generate a changeLog file that contains the differences between two existing databases:

mvn liquibase:diff

We can then use this file to align two databases. For this to work correctly, we need to configure the liquibase plugin with additional properties:

changeLogFile=src/main/resources/config/liquibase/master.xml
url=jdbc:h2:file:./target/h2db/db/carapp 
username=carapp 
password= 
driver=com.mysql.jdbc.Driver 
referenceUrl=jdbc:h2:file:./target/h2db/db/carapp2 
referenceDriver=org.h2.Driver 
referenceUsername=tutorialuser2 
referencePassword=tutorialmy5ql2

Again, this will generate a changeLog file:

<databaseChangeLog ...>
    <changeSet author="John" id="1439227853089-1">
        <dropColumn columnName="brand" tableName="car"/>
    </changeSet>
</databaseChangeLog>

This is a super powerful way to evolve our DB. For example, we could allow Hibernate to auto-generate a new schema for development and then use that as a reference point against the old schema.

7. Use the Liquibase Hibernate Plugin

If our application uses Hibernate, we can use the liquibase-hibernate5 to generate the changeLog file.

7.1. Plugin Configuration

First, let’s add the latest version of the dependency in our pom.xml:

<plugin>
   <groupId>org.liquibase</groupId>
   <artifactId>liquibase-maven-plugin</artifactId>
   <version>4.27.0</version>
   <dependencies>
      ...
      <dependency>
         <groupId>org.liquibase.ext</groupId>
         <artifactId>liquibase-hibernate5</artifactId>
         <version>3.6</version>
      </dependency>
     ...
   </dependencies>
   ...
</plugin>

7.2. Generate a changelog From Diffs Between a Database and Persistence Entities

Now, we can use this plugin to generate a changelog file based on the differences between an existing database (for example, production) and our new persistence entities.

So, to make things simple, once an entity is modified, we can generate the changes against the old DB schema, getting a clean, powerful way to evolve our schema in production.

Here are the liquibase properties in our plugin configuration inside the pom.xml:

<configuration>
   <changeLogFile>src/main/resources/config/liquibase/master.xml</changeLogFile>
   <diffChangeLogFile>src/main/resources/config/liquibase/changelog/${maven.build.timestamp}_changelog.xml</diffChangeLogFile>
   <driver>org.h2.Driver</driver>
   <url>jdbc:h2:file:./target/h2db/db/carapp</url>
   <defaultSchemaName />
   <username>carapp</username>
   <password />
   <referenceUrl>hibernate:spring:com.car.app.domain?dialect=org.hibernate.dialect.H2Dialect
    &hibernate.physical_naming_strategy=org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy
    &hibernate.implicit_naming_strategy=org.springframework.boot.orm.jpa.hibernate.SpringImplicitNamingStrategy
   </referenceUrl>
   <verbose>true</verbose>
   <logging>debug</logging>
</configuration>

Notably, the referenceUrl is using package scan, so the dialect parameter is required.

8. Generate the changelog in IntelliJ IDEA Using the JPA Buddy Plugin

If we’re using a non-Hibernate ORM (e.g., EclipseLink or OpenJPA) or we don’t want to add extra dependencies like the liquibase-hibernate plugin, we can use JPA Buddy. This IntelliJ IDEA plugin integrates useful Liquibase features into the IDE.

To generate a differential changelog, we install the plugin and then call the action from the JPA Structure panel. We select the source we want to compare (database, JPA entities or Liquibase snapshot) with the target (database or Liquibase snapshot).

JPA Buddy will generate the changeLog as shown in the animation below:

jpabuddy_intellij

Another advantage of JPA Buddy over the liquibase-hibernate plugin is the ability to override default mappings between Java and database types. Also, it works correctly with Hibernate custom types and JPA converters.

9. Conclusion

In this article, we illustrated several ways to use Liquibase and get to a safe and mature way of evolving and refactoring the DB schema of a Java app.

The code backing this article is available on GitHub. Once you're logged in as a Baeldung Pro Member, start learning and coding on the project.
Baeldung Pro – NPI EA (cat = Baeldung)
announcement - icon

Baeldung Pro comes with both absolutely No-Ads as well as finally with Dark Mode, for a clean learning experience:

>> Explore a clean Baeldung

Once the early-adopter seats are all used, the price will go up and stay at $33/year.

Partner – Microsoft – NPI EA (cat = Spring Boot)
announcement - icon

Azure Container Apps is a fully managed serverless container service that enables you to build and deploy modern, cloud-native Java applications and microservices at scale. It offers a simplified developer experience while providing the flexibility and portability of containers.

Of course, Azure Container Apps has really solid support for our ecosystem, from a number of build options, managed Java components, native metrics, dynamic logger, and quite a bit more.

To learn more about Java features on Azure Container Apps, visit the documentation page.

You can also ask questions and leave feedback on the Azure Container Apps GitHub page.

Partner – Orkes – NPI EA (cat = Spring)
announcement - icon

Modern software architecture is often broken. Slow delivery leads to missed opportunities, innovation is stalled due to architectural complexities, and engineering resources are exceedingly expensive.

Orkes is the leading workflow orchestration platform built to enable teams to transform the way they develop, connect, and deploy applications, microservices, AI agents, and more.

With Orkes Conductor managed through Orkes Cloud, developers can focus on building mission critical applications without worrying about infrastructure maintenance to meet goals and, simply put, taking new products live faster and reducing total cost of ownership.

Try a 14-Day Free Trial of Orkes Conductor today.

Partner – Orkes – NPI EA (tag = Microservices)
announcement - icon

Modern software architecture is often broken. Slow delivery leads to missed opportunities, innovation is stalled due to architectural complexities, and engineering resources are exceedingly expensive.

Orkes is the leading workflow orchestration platform built to enable teams to transform the way they develop, connect, and deploy applications, microservices, AI agents, and more.

With Orkes Conductor managed through Orkes Cloud, developers can focus on building mission critical applications without worrying about infrastructure maintenance to meet goals and, simply put, taking new products live faster and reducing total cost of ownership.

Try a 14-Day Free Trial of Orkes Conductor today.

eBook – HTTP Client – NPI EA (cat=HTTP Client-Side)
announcement - icon

The Apache HTTP Client is a very robust library, suitable for both simple and advanced use cases when testing HTTP endpoints. Check out our guide covering basic request and response handling, as well as security, cookies, timeouts, and more:

>> Download the eBook

eBook – Java Concurrency – NPI EA (cat=Java Concurrency)
announcement - icon

Handling concurrency in an application can be a tricky process with many potential pitfalls. A solid grasp of the fundamentals will go a long way to help minimize these issues.

Get started with understanding multi-threaded applications with our Java Concurrency guide:

>> Download the eBook

eBook – Java Streams – NPI EA (cat=Java Streams)
announcement - icon

Since its introduction in Java 8, the Stream API has become a staple of Java development. The basic operations like iterating, filtering, mapping sequences of elements are deceptively simple to use.

But these can also be overused and fall into some common pitfalls.

To get a better understanding on how Streams work and how to combine them with other language features, check out our guide to Java Streams:

>> Join Pro and download the eBook

eBook – Persistence – NPI EA (cat=Persistence)
announcement - icon

Working on getting your persistence layer right with Spring?

Explore the eBook

Course – LS – NPI EA (cat=REST)

announcement - icon

Get started with Spring Boot and with core Spring, through the Learn Spring course:

>> CHECK OUT THE COURSE

Course – Spring Sale 2025 – NPI EA (cat= Baeldung)
announcement - icon

Yes, we're now running our Spring Sale. All Courses are 25% off until 26th May, 2025:

>> EXPLORE ACCESS NOW

Course – Spring Sale 2025 – NPI (All)
announcement - icon

Yes, we're now running our Spring Sale. All Courses are 25% off until 26th May, 2025:

>> EXPLORE ACCESS NOW

eBook Jackson – NPI EA – 3 (cat = Jackson)