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 – 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

Accessibility testing is a crucial aspect to ensure that your application is usable for everyone and meets accessibility standards that are required in many countries.

By automating these tests, teams can quickly detect issues related to screen reader compatibility, keyboard navigation, color contrast, and other aspects that could pose a barrier to using the software effectively for people with disabilities.

Learn how to automate accessibility testing with Selenium and the LambdaTest cloud-based testing platform that lets developers and testers perform accessibility automation on over 3000+ real environments:

Automated Accessibility Testing With Selenium

1. Overview

Liquibase is a powerful database management tool that provides an easy way to track and deploy database changes. It also allows to describe the behavior of changesets at the time of their deployment through what we call metadata.

Preconditions are a form of metadata commonly used to control the execution of a changelog or individual changesets. They ensure that certain requirements are met before continuing deployment.

In this tutorial, we’ll explore preconditions and learn to define conditional logic and error handling to optimize changeset control during their deployment.

2. Understanding Preconditions

Preconditions are an essential feature of Liquibase. They let us define specific conditions that must be satisfied before applying a changeset or changes. So, we can think of preconditions as guardians of database changes.

Before deploying a changeset, Liquibase systematically evaluates these conditions. If the conditions aren’t met, Liquibase prevents the changeset from being executed. Depending on the precondition behavior, it can throw failures or warnings or skip the changeset. This mechanism ensures that changes apply only when the database state meets the required criteria. In this way, we can ensure rigorous control of deployments while minimizing the risk of problems or errors.

Let’s explore a few practical scenarios where Liquibase preconditions can be useful:

  • We can restrict changes to a specific database type, a group of database types, or even a particular version to ensure compatibility.
  • We can check whether an object in the database already exists before creating or modifying it, thus avoiding unexpected errors.
  • It also makes sense to check existing data before performing irreversible changes. For example, we can prevent the deletion of a table (dropTable) if it still contains data.
  • Finally, we can validate the presence or absence of specific data before making any changes. For instance, if a migration involves inserting a new row into a configuration table, we can ensure this row doesn’t already exist, to avoid duplication or inconsistency.

These practices help us to secure our deployments and better anticipate potential problems.

3. Defining Preconditions Syntax

Preconditions are tags that we add directly to the changelog file to control the execution of changes. Let’s talk about their syntax.

3.1. Basic Syntax of Preconditions

Let’s start by using a simple example:

<preConditions>
    <dbms type="mysql,oracle" />
</preConditions>

Here we use the dbms precondition. This ensures that the database is either MySQL or Oracle.

Liquibase offers several precondition tags that fit our needs. Here are some examples of preconditions:

  • dbms checks the database type
  • runningAs verifies the database username
  • tableExists checks whether a table exists
  • columnExists ensures the presence of a specific column
  • foreignKeyExists checks whether a foreign key exists
  • sqlCheck executes a SQL query and compares it with the expected result

We can define these preconditions in various changelog file formats such as XML, YAML, or JSON. Prior to Liquibase 4.27.0, only sqlCheck was compatible with the formatted SQL. As of version 4.27.0, other preconditions like tableExists and viewExists also support SQL changelogs:

--precondition-table-exists table:users

This is a valuable improvement for users who prefer to work with SQL changelogs.

We can always refer to the official documentation for a complete list of available preconditions and their attributes.

3.2. Nested Preconditions

Liquibase gives us the flexibility to nest or wrap multiple preconditions using logical tags like <and>, <or> and <not>. This makes it possible to create more complex conditions.

Let’s look at an example:

<preConditions>  
    <or>  
        <and>  
            <dbms type="oracle" />  
            <runningAs username="baeldung" />  
        </and>  
        <and>  
            <dbms type="mysql" />  
            <runningAs username="baeldung" />  
        </and>  
    </or>  
</preConditions>

In this example, we check whether the database is Oracle and the database user is baeldung or whether the database is MySQL with the same user.

If no logical operator is specified, Liquibase applies AND logic by default. Let’s take another example:

<preConditions>  
    <tableExists tableName="users"/>  
    <columnExists tableName="users" columnName="email"/>  
</preConditions> 

In this case, both conditions must be met: the users table must exist and it must contain an email column.

Liquibase uses lazy evaluation for preconditions. This means that if the first condition in an <and> fails, the next one isn’t even checked. Similarly, if the first condition in an <or> fails, it skips the remaining conditions.

4. Global vs Local Preconditions

We can use preconditions at two levels: globally in the changelog, and locally in each changeset.

Global or changelog preconditions are defined at the top of the changelog, prior to any changesets. They apply to all changesets, and are useful for general checks, such as ensuring that the database is compatible:

<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">
    
    <preConditions>
        <dbms type="mysql"/>
        <runningAs username="baeldung"/>
        <sqlCheck expectedResult="9.1.0">
            SELECT @@version;
        </sqlCheck>
    </preConditions>

    <changeSet id="BAEL-1000" author="baeldung">
        <addColumn tableName="users">
            <column name="country" type="varchar(25)"/>
        </addColumn>
    </changeSet>

    <changeSet id="BAEL-1001" author="baeldung">
        <addColumn tableName="tutorials">
            <column name="code" type="varchar(5)"/>
        </addColumn>
    </changeSet>

</databaseChangeLog>

In this example, we checked that the database is MySQL and that the database user deploying the changesets is baeldung. We also checked the database version is 9.1.0 using sqlCheck. Therefore, if any of these conditions aren’t met, none of the changesets will be executed.

Local preconditions, on the other hand, are defined at the top of a changeset and apply only to that specific changeset. They enable targeted checks, such as ensuring that a table or column exists before applying a change.

Let’s take an example:

<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">
                   
    <changeSet id="BAEL-1000" author="baeldung">
        <addColumn tableName="users">
            <column name="country" type="varchar(25)"/>
        </addColumn>
    </changeSet>

    <changeSet id="BAEL-1002" author="baeldung">
        <preConditions>
            <tableExists tableName="users"/>
            <columnExists tableName="users" columnName="last_visit"/>
        </preConditions>
    
        <dropColumn tableName="users" columnName="last_visit"/>
    </changeSet>

</databaseChangeLog>

This precondition only applies to the changeset with the id BAEL-1002. It ensures that the users table and the last_visit column exist before allowing the column to be dropped.

5. Handling Preconditions Failures and Errors

Liquibase distinguishes between a precondition failure and an error during its execution:

  • A failure happens when a precondition runs successfully but doesn’t meet the expected criteria.
  • An error occurs when technical issues, like a syntax error, prevent the precondition from running.

We use the onFail and onError attributes to specify how to handle failures or errors during precondition checks.

5.1. The onFail and onError Attributes

Let’s look at a changelog example with a changeset that includes a precondition:

<changeSet id="BAEL-1003" author="baeldung">
    <preConditions onFail="HALT" onError="HALT">
        <not>
            <columnExists tableName="users" columnName="verified"/>
        </not>
    </preConditions>
    
    <addColumn tableName="users">
        <column name="verified" type="boolean" defaultValue="false"/>
    </addColumn>
</changeSet>

We can run this changelog using the mvn liquibase:update command.

If the verified column already exists, the precondition fails with the following message:

Not precondition failed

For instance, if the users table doesn’t exist, an error occurs:

liquibase.exception.DatabaseException: Table 'baeldung_liquibase.users' doesn't exist

In both cases, the HALT value immediately stops execution when there’s a failure or error.

5.2. Values for onFail and onError Attributes

We can configure different behaviors for handling preconditions:

  • HALT immediately stops the changelog execution. This is the default behavior.
  • WARN logs a warning but continues execution
  • MARK_RAN marks the changeSet as executed in DATABASECHANGELOG table and continues
  • CONTINUE skips the changeSet and proceeds with execution

The table below summarizes the possible values:

onFail Attribute Values onError Attribute Values
Global Precondition HALT, WARN HALT, WARN
Local Precondition HALT, CONTINUE, MARK_RAN, WARN HALT, CONTINUE, MARK_RAN, WARN

Additional attributes, like onErrorMessage and onFailMessage, enable customized error or failure messages:

<preConditions onFail="WARN" onFailMessage="Column verified already exists">
    <not>
        <columnExists tableName="users" columnName="verified"/>
    </not>
</preConditions>

These attributes allow flexibility and provide custom behavior when handling preconditions.

6. Conclusion

In this article, we explored how Liquibase preconditions improve control and precision during database updates. They ensure the database meets specific conditions before applying changes. This approach reduces risks and avoids potential errors.

By effectively utilizing preconditions, we can streamline deployments and maintain database integrity.

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 – 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

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