Liquibase Attributes runAlways

Liquibase runs the update command to execute the ChangeSet and with each successful execution, it adds a row in DATABASECHANGELOG table with the execution date, deployment ID, and MD5 checksum to keep track of executed ChangeSet. each ChangeSet is distinguished by unique id property.

 <changeSet author="wesome (generated)" id="1692523877432-1">

let's see with an example, below is the ChangeLog file for creating a table ChangeSet with id=1692523877432-1, and an insert record ChangeSet with id=1692523877432-1.

changelog.mysql.xml

<?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 (generated)" id="1692523877432-1">
        <createTable catalogName="appledb" tableName="apple">
            <column 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 (generated)" id="1692523877432-2">
        <insert catalogName="appledb" tableName="apple">
            <column name="apple_id" valueNumeric="1"/>
            <column name="apple_name" value="Macintosh"/>
            <column name="current_date_time" valueDate="now()"/>
        </insert>
    </changeSet>
</databaseChangeLog>

liquibase.properties (update changeLogFile file format with SQL, XML, YAML, JSON as per changelog.mysql.<format>)

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

run update command

liquibase update

Liquibase has printed the number of ChangeSet executed in the logs

Running Changeset: changelog.mysql.xml::1692523877432-1::wesome (generated)
Running Changeset: changelog.mysql.xml::1692523877432-2::wesome (generated)

UPDATE SUMMARY
Run:                          2
Previously run:               0
Filtered out:                 0
-------------------------------
Total change sets:            2

Liquibase: Update has been successful.

query DATABASECHANGELOG table, the id column has the same values of id attributes of ChangeSet.

select * from appledb.DATABASECHANGELOG;

How Liquibase checks for existing changeset id

in consecutive deployments, Liquibase matches for id column of DATABASECHANGELOG with the ChangeSet id, and if the same then Liquibase will ignore the ChangeSet and execute the next one. let's see the same with an example

below is the ChangeLog file contains 2 ChangeSet, 1 for creating a table ChangeSet with id=1692523877432-1, and another for inserting a record ChangeSet with id=1692523877432-1.

changelog.mysql.xml

<?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 (generated)" id="1692523877432-1">
        <createTable catalogName="appledb" tableName="apple">
            <column 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 (generated)" id="1692523877432-2">
        <insert catalogName="appledb" tableName="apple">
            <column name="apple_id" valueNumeric="1"/>
            <column name="apple_name" value="Macintosh"/>
            <column name="current_date_time" valueDate="now()"/>
        </insert>
    </changeSet>
</databaseChangeLog>

liquibase.properties (update changeLogFile file format with SQL, XML, YAML, JSON as per changelog.mysql.<format>)

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

run the update command

liquibase update

Liquibase has printed the number of ChangeSet executed in the logs

Running Changeset: changelog.mysql.xml::1692523877432-1::wesome (generated)
Running Changeset: changelog.mysql.xml::1692523877432-2::wesome (generated)

UPDATE SUMMARY
Run:                          2
Previously run:               0
Filtered out:                 0
-------------------------------
Total change sets:            2

Liquibase: Update has been successful.

query DATABASECHANGELOG table, the id column has the same values of id attributes of ChangeSet.

select * from appledb.DATABASECHANGELOG;

Now let's see the Apple table in the AppleDB schema.

select * from appledb.apple;

It is showing an apple table with 1 record inserted, run the update command again and notice the logs

liquibase update

Liquibase has printed the number of ChangeSet executed in the logs

Running Changeset: changelog.mysql.xml::1692523877432-1::wesome (generated)
Running Changeset: changelog.mysql.xml::1692523877432-2::wesome (generated)

UPDATE SUMMARY
Run:                          0
Previously run:               2
Filtered out:                 0
-------------------------------
Total change sets:            0

Liquibase: Update has been successful.

Liquibase matched the ChangeSet id with the id of DATABASECHANGELOG table and noticed both the changeset has been already executed hence skip both.

Liquibase skip already executed the ChangeSet but run a new changeset

We learned that Liquibase ignores the expected changeset, but what will happen if a new ChangeSet with a new id appears in the changelog file? well Liquibase will ignore previously executed ChangeSet as per default behavior but will execute the new ChangeSet.

Let's update the same ChangeLog file and append another insert record ChangeSet in the same ChangeLog file keeping the existing ChangeSet intact.

changelog.mysql.xml

<?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 (generated)" id="1692523877432-1">
        <createTable catalogName="appledb" tableName="apple">
            <column 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 (generated)" id="1692523877432-2">
        <insert catalogName="appledb" tableName="apple">
            <column name="apple_id" valueNumeric="1"/>
            <column name="apple_name" value="Macintosh"/>
            <column name="current_date_time" valueDate="now()"/>
        </insert>
    </changeSet>
    <changeSet author="shriksha (generated)" id="1692523877432-3">
        <insert catalogName="appledb" tableName="apple">
            <column name="apple_id" valueNumeric="2"/>
            <column name="apple_name" value="Fuji"/>
            <column name="current_date_time" valueDate="now()"/>
        </insert>
    </changeSet>
</databaseChangeLog>

liquibase.properties (update changeLogFile file format with SQL, XML, YAML, JSON as per changelog.mysql.<format>)

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

run the update command

liquibase update

Liquibase matched the existing ChangeSet with DATABASECHANGELOG table and noticed that the ChangeSet id 1692523877432-1 and 1692523877432-2 has already been executed before hence skipped those and ran the latest one. printed the number of ChangeSet executed in the logs

Running Changeset: changelog.mysql.xml::1692523877432-3::wesome (generated)

UPDATE SUMMARY
Run:                          1
Previously run:               2
Filtered out:                 0
-------------------------------
Total change sets:            3

Liquibase: Update has been successful.

query DATABASECHANGELOG table, the id column has the same values of id attributes of ChangeSet.

select * from appledb.DATABASECHANGELOG;

Now let's see the Apple table in the AppleDB schema.

select * from appledb.apple;

It is showing apple table with 2 records inserted, the new ChanegSet has been inserted without actually modifying the existing data.

Run changeset every time irrespective of previous executions with runAlways attribute

Some times requirement is to execute a ChangeSet every time irrespective of its previous successful executions, such as updating the TimeStamp, restoring default values after every time interval, etc. Liquibase provides a runAlways attribute to run ChangeSet every time deployment happens.

Let's take the same example as above, below CahngeLog has 3 ChangeSet of table creation, record insertion, and record updation.

<?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 (generated)" id="1692523877432-1">
        <createTable catalogName="appledb" tableName="apple">
            <column 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 (generated)" id="1692523877432-2">
        <insert catalogName="appledb" tableName="apple">
            <column name="apple_id" valueNumeric="1"/>
            <column name="apple_name" value="Macintosh"/>
            <column name="current_date_time" valueDate="now()"/>
        </insert>
    </changeSet>
    <changeSet author="wesome (generated)" id="1692523877432-3" runAlways="true">
        <update  catalogName="appledb" tableName="apple">
        <column  name="current_date_time"  valueDate="now()"/>
    </update>
    </changeSet>
</databaseChangeLog>

liquibase.properties (update changeLogFile file format with SQL, XML, YAML, JSON as per changelog.mysql.<format>)

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

run the update command

liquibase update

Liquibase has printed the number of ChangeSet executed in the logs

Running Changeset: changelog.mysql.xml::1692523877432-1::wesome (generated)
Running Changeset: changelog.mysql.xml::1692523877432-2::wesome (generated)

UPDATE SUMMARY
Run:                          1
Previously run:               2
Filtered out:                 0
-------------------------------
Total change sets:            3

Liquibase: Update has been successful.

Query the Apple table in the AppleDB schema.

select * from appledb.apple;

Notice the date column of the apple table, the record has been updated.

runAlways only works with the update command, not create or insert.

as per the above examples, the attribute runAlways is working fine with the updated changeset, because it has to update the existing record every time.

    <changeSet author="wesome (generated)" id="1692523877432-3" runAlways="true">
        <update  catalogName="appledb" tableName="apple">
        <column  name="current_date_time"  valueDate="now()"/>
    </update>
    </changeSet>

but if attribute runAlways added with create or insert attribute then it runs perfectly for the first time but will throw an error from the second deployment onwards.

<?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="shriksha (generated)" id="1692523877432-1" runAlways="true">
        <createTable catalogName="appledb" tableName="apple">
            <column 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>
</databaseChangeLog>

 run the update command

liquibase update

Liquibase has printed the number of ChangeSet executed in the logs

Running Changeset: changelog.mysql.xml::1692523877432-1::shriksha (generated)

UPDATE SUMMARY
Run:                          1
Previously run:               0
Filtered out:                 0
-------------------------------
Total change sets:            1

Liquibase: Update has been successful.

Liquibase has successfully executed the ChangeSet for the first time. now run the update command again.

liquibase update

Liquibase has printed the number of ChangeSet executed in the logs

Running Changeset: changelog.mysql.xml::1692523877432-1::shriksha (generated)

Unexpected error running Liquibase: Migration failed for changeset changelog.mysql.xml::1692523877432-1::shriksha (generated):
     Reason: liquibase.exception.DatabaseException: Table 'apple' already exists [Failed SQL: (1050) CREATE TABLE appledb.apple (apple_id BIGINT NOT NULL, apple_name VARCHAR(255) NULL, current_date_time datetime DEFAULT NOW() NULL, CONSTRAINT PK_APPLE PRIMARY KEY (apple_id))]

For more information, please use the --log-level flag

The execution will fail because runAlways trying to create a table that already exists in the database.

follow us on