Preconditions
are used to check if the database has all the requirements met for the ChangeSet
to run to avoid any future errors. If Preconditions
passes, Liquibase
will execute the ChangeSet
successfully, but if Preconditions
fails and the Database doesn't meet all necessary requirements, Liquibase
allows modification of the execution behaviors.
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog" xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext" xmlns:pro="http://www.liquibase.org/xml/ns/pro" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog-ext http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd http://www.liquibase.org/xml/ns/pro http://www.liquibase.org/xml/ns/pro/liquibase-pro-latest.xsd http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-latest.xsd">
<changeSet author="wesome" id="1692599548266-1">
<createTable catalogName="appledb" tableName="apple">
<column autoIncrement="true" name="apple_id" type="BIGINT">
<constraints nullable="false" primaryKey="true" />
</column>
<column name="apple_name" type="VARCHAR(255)" />
<column defaultValueComputed="CURRENT_TIMESTAMP" name="current_date_time" type="datetime" />
</createTable>
</changeSet>
<changeSet author="wesome" id="1692599548266-2">
<preConditions>
<rowCount expectedRows="5" tableName="apple" />
</preConditions>
<insert catalogName="appledb" tableName="apple">
<column name="apple_id" />
<column name="apple_name" value="Macintosh" />
<column name="current_date_time" valueDate="now()" />
</insert>
</changeSet>
<changeSet author="wesome" id="1692599548266-3">
<insert catalogName="appledb" tableName="apple">
<column name="apple_id" />
<column name="apple_name" value="Gala" />
<column name="current_date_time" valueDate="now()" />
</insert>
</changeSet>
</databaseChangeLog>
liquibase.properties (update changeLog File file format with SQL, XML, YAML, JSON as per changelog.mysql.)
changeLogFile=changelog.mysql.xml
liquibase.command.url:jdbc:mysql://localhost:3306/appleDb?createDatabaseIfNotExist=true&autoReconnect=true&useSSL=false&allowPublicKeyRetrieval=true
liquibase.command.username : root
liquibase.command.password : rootroot
The above Preconditions
is checking that the apple table should have at least 5 rows, but it results in an error because the apple table exists but it doesn't have 5 records.
Running Changeset: changelog.mysql.xml::1692599548266-1::wesome
Running Changeset: changelog.mysql.xml::1692599548266-2::wesome
Unexpected error running Liquibase: Migration failed for changeset changelog.mysql.xml::1692599548266-2::wesome:
Reason:
changelog.mysql.xml : Table apple does not have the expected row count of 5. It contains 0 rows
- Caused by: Preconditions Failed
Custom message for Preconditions Fail
Liquibase
provides an onFailMessage
attribute to provide custom messages when an error occurs.
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog" xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext" xmlns:pro="http://www.liquibase.org/xml/ns/pro" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog-ext http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd http://www.liquibase.org/xml/ns/pro http://www.liquibase.org/xml/ns/pro/liquibase-pro-latest.xsd http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-latest.xsd">
<changeSet author="wesome" id="1692599548266-1">
<createTable catalogName="appledb" tableName="apple">
<column autoIncrement="true" name="apple_id" type="BIGINT">
<constraints nullable="false" primaryKey="true" />
</column>
<column name="apple_name" type="VARCHAR(255)" />
<column defaultValueComputed="CURRENT_TIMESTAMP" name="current_date_time" type="datetime" />
</createTable>
</changeSet>
<changeSet author="wesome" id="1692599548266-2">
<preConditions onFailMessage="condition fail:- apple table should have minimum 5 rows">
<rowCount expectedRows="5" tableName="apple" />
</preConditions>
<insert catalogName="appledb" tableName="apple">
<column name="apple_id" />
<column name="apple_name" value="Macintosh" />
<column name="current_date_time" valueDate="now()" />
</insert>
</changeSet>
<changeSet author="wesome" id="1692599548266-3">
<insert catalogName="appledb" tableName="apple">
<column name="apple_id" />
<column name="apple_name" value="Gala" />
<column name="current_date_time" valueDate="now()" />
</insert>
</changeSet>
</databaseChangeLog>
liquibase.properties (update changeLog File file format with SQL, XML, YAML, JSON as per changelog.mysql.)
changeLogFile=changelog.mysql.xml
liquibase.command.url:jdbc:mysql://localhost:3306/appleDb?createDatabaseIfNotExist=true&autoReconnect=true&useSSL=false&allowPublicKeyRetrieval=true
liquibase.command.username : root
liquibase.command.password : rootroot
Preconditions onFail attributes
To deal with Preconditions failure scenarios, Liquibase
provides an onFail
attribute, that controls what should happen if Preconditions
doesn't pass onFail
supports CONTINUE, HALT, MARK_RAN, WARN. Let's see them one by one.
Preconditions onFail Continue
onFail=CONTINUE
will skip the current ChangeSet
and will continue with the next ChangeSet
in the ChangeLog
file. Liquibase
will try to execute this ChangeSet
on the next update.
In the below example ChangeSet id="1692599548266-2
checking if the table already has 1 record, but since it is a new table, there will not be any record, and Precondition
fails.
but with onFail="CONTINUE"
, liquibase migrator will skip the ChangeSet
and continue execution of the next ChangeSet
.
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog" xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext" xmlns:pro="http://www.liquibase.org/xml/ns/pro" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog-ext http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd http://www.liquibase.org/xml/ns/pro http://www.liquibase.org/xml/ns/pro/liquibase-pro-latest.xsd http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-latest.xsd">
<changeSet author="wesome" id="1692599548266-1">
<createTable catalogName="appledb" tableName="apple">
<column autoIncrement="true" name="apple_id" type="BIGINT">
<constraints nullable="false" primaryKey="true" />
</column>
<column name="apple_name" type="VARCHAR(255)" />
<column defaultValueComputed="CURRENT_TIMESTAMP" name="current_date_time" type="datetime" />
</createTable>
</changeSet>
<changeSet author="wesome" id="1692599548266-2">
<preConditions onFail="CONTINUE" onFailMessage="condition fail:- apple table should have minimum 5 rows">
<rowCount expectedRows="5" tableName="apple" />
</preConditions>
<insert catalogName="appledb" tableName="apple">
<column name="apple_id" />
<column name="apple_name" value="Macintosh" />
<column name="current_date_time" valueDate="now()" />
</insert>
</changeSet>
<changeSet author="wesome" id="1692599548266-3">
<insert catalogName="appledb" tableName="apple">
<column name="apple_id" />
<column name="apple_name" value="Gala" />
<column name="current_date_time" valueDate="now()" />
</insert>
</changeSet>
</databaseChangeLog>
liquibase.properties (update changeLog File file format with SQL, XML, YAML, JSON as per changelog.mysql.)
changeLogFile=changelog.mysql.xml
liquibase.command.url:jdbc:mysql://localhost:3306/appleDb?createDatabaseIfNotExist=true&autoReconnect=true&useSSL=false&allowPublicKeyRetrieval=true
liquibase.command.username : root
liquibase.command.password : rootroot
Preconditions onFail Halt
onFail=HALT
will abort the execution of the entire ChangeLog
file. HALT
is the default value of onError.
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog" xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext" xmlns:pro="http://www.liquibase.org/xml/ns/pro" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog-ext http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd http://www.liquibase.org/xml/ns/pro http://www.liquibase.org/xml/ns/pro/liquibase-pro-latest.xsd http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-latest.xsd">
<changeSet author="wesome" id="1692599548266-1">
<createTable catalogName="appledb" tableName="apple">
<column autoIncrement="true" name="apple_id" type="BIGINT">
<constraints nullable="false" primaryKey="true" />
</column>
<column name="apple_name" type="VARCHAR(255)" />
<column defaultValueComputed="CURRENT_TIMESTAMP" name="current_date_time" type="datetime" />
</createTable>
</changeSet>
<changeSet author="wesome" id="1692599548266-2">
<preConditions onFail="HALT" onFailMessage="condition fail:- apple table should have minimum 5 rows">
<rowCount expectedRows="5" tableName="apple" />
</preConditions>
<insert catalogName="appledb" tableName="apple">
<column name="apple_id" />
<column name="apple_name" value="Macintosh" />
<column name="current_date_time" valueDate="now()" />
</insert>
</changeSet>
<changeSet author="wesome" id="1692599548266-3">
<insert catalogName="appledb" tableName="apple">
<column name="apple_id" />
<column name="apple_name" value="Gala" />
<column name="current_date_time" valueDate="now()" />
</insert>
</changeSet>
</databaseChangeLog>
liquibase.properties (update changeLog File file format with SQL, XML, YAML, JSON as per changelog.mysql.)
changeLogFile=changelog.mysql.xml
liquibase.command.url:jdbc:mysql://localhost:3306/appleDb?createDatabaseIfNotExist=true&autoReconnect=true&useSSL=false&allowPublicKeyRetrieval=true
liquibase.command.username : root
liquibase.command.password : rootroot
Preconditions onFail MARK RAN
onFail=MARK_RAN
will skip the execution of the current ChangeSet
but it will mark the current ChangeSet
as executed in DATABASECHANGELOG
table, and continue with the next ChangeSet
.
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog" xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext" xmlns:pro="http://www.liquibase.org/xml/ns/pro" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog-ext http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd http://www.liquibase.org/xml/ns/pro http://www.liquibase.org/xml/ns/pro/liquibase-pro-latest.xsd http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-latest.xsd">
<changeSet author="wesome" id="1692599548266-1">
<createTable catalogName="appledb" tableName="apple">
<column autoIncrement="true" name="apple_id" type="BIGINT">
<constraints nullable="false" primaryKey="true" />
</column>
<column name="apple_name" type="VARCHAR(255)" />
<column defaultValueComputed="CURRENT_TIMESTAMP" name="current_date_time" type="datetime" />
</createTable>
</changeSet>
<changeSet author="wesome" id="1692599548266-2">
<preConditions onFail="MARK_RAN" onFailMessage="condition fail:- apple table should have minimum 5 rows">
<rowCount expectedRows="5" tableName="apple" />
</preConditions>
<insert catalogName="appledb" tableName="apple">
<column name="apple_id" />
<column name="apple_name" value="Macintosh" />
<column name="current_date_time" valueDate="now()" />
</insert>
</changeSet>
<changeSet author="wesome" id="1692599548266-3">
<insert catalogName="appledb" tableName="apple">
<column name="apple_id" />
<column name="apple_name" value="Gala" />
<column name="current_date_time" valueDate="now()" />
</insert>
</changeSet>
</databaseChangeLog>
liquibase.properties (update changeLog File file format with SQL, XML, YAML, JSON as per changelog.mysql.)
changeLogFile=changelog.mysql.xml
liquibase.command.url:jdbc:mysql://localhost:3306/appleDb?createDatabaseIfNotExist=true&autoReconnect=true&useSSL=false&allowPublicKeyRetrieval=true
liquibase.command.username : root
liquibase.command.password : rootroot
Even though the ChangeSet
has failed, it still is marked as executed successfully and can be verified by running a query
select * from appledb.DATABASECHANGELOG;
Preconditions onFail WARN
onError=WARN
will send a warning about a failed Preconditions
, it will skip the current ChangeSet
execution, but mark it as executed in DATABASECHANGELOG
table and continue executing the next ChangeSet
.
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog" xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext" xmlns:pro="http://www.liquibase.org/xml/ns/pro" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog-ext http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd http://www.liquibase.org/xml/ns/pro http://www.liquibase.org/xml/ns/pro/liquibase-pro-latest.xsd http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-latest.xsd">
<changeSet author="wesome" id="1692599548266-1">
<createTable catalogName="appledb" tableName="apple">
<column autoIncrement="true" name="apple_id" type="BIGINT">
<constraints nullable="false" primaryKey="true" />
</column>
<column name="apple_name" type="VARCHAR(255)" />
<column defaultValueComputed="CURRENT_TIMESTAMP" name="current_date_time" type="datetime" />
</createTable>
</changeSet>
<changeSet author="wesome" id="1692599548266-2">
<preConditions onFail="WARN" onFailMessage="condition fail:- apple table should have minimum 5 rows">
<rowCount expectedRows="5" tableName="apple" />
</preConditions>
<insert catalogName="appledb" tableName="apple">
<column name="apple_id" />
<column name="apple_name" value="Macintosh" />
<column name="current_date_time" valueDate="now()" />
</insert>
</changeSet>
<changeSet author="wesome" id="1692599548266-3">
<insert catalogName="appledb" tableName="apple">
<column name="apple_id" />
<column name="apple_name" value="Gala" />
<column name="current_date_time" valueDate="now()" />
</insert>
</changeSet>
</databaseChangeLog>
liquibase.properties (update changeLog File file format with SQL, XML, YAML, JSON as per changelog.mysql.)
changeLogFile=changelog.mysql.xml
liquibase.command.url:jdbc:mysql://localhost:3306/appleDb?createDatabaseIfNotExist=true&autoReconnect=true&useSSL=false&allowPublicKeyRetrieval=true
liquibase.command.username : root
liquibase.command.password : rootroot
Liquibase
will print the warning on the log as well
Running Changeset: changelog.mysql.xml::1692599548266-1::wesome
Running Changeset: changelog.mysql.xml::1692599548266-2::wesome
WARNING: Executing changelog.mysql.xml::1692599548266-2::wesome despite precondition failure due to onFail='WARN':
condition fail:- apple table should have minimum 5 rows
Running Changeset: changelog.mysql.xml::1692599548266-3::wesome
The ChangeSet
has been marked as executed and can be verified by running the query
select * from appledb.DATABASECHANGELOG;