Liquibase Attributes runOrder

The Liquibase migrator executes ChangeSet sequentially according to the ChangeLog file. The ChangeSet on top will run first and the change on the bottom will run later, but sometimes the requirement is to run some ChangeSet at the very beginning or at the very end of execution.
One solution is to move the ChangeSet at the beginning or at the end of the ChangeLog file which is very error-prone. Let's see the same with an example
Table Apple has an auto-increment primary key, so whichever ChangeSet runs first will be assigned the primary key in order.

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" 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-3">
		<insert catalogName="appledb" tableName="apple">
			<column name="apple_id" />
			<column name="apple_name" value="Fuji" />
			<column name="current_date_time" valueDate="now()" />
		</insert>
	</changeSet>
	<changeSet author="wesome" id="1692599548266-2">
		<insert catalogName="appledb" tableName="apple">
			<column name="apple_id" />
			<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

query apple table
select * from appledb.apple;

ChangeSet with apple_name=Fuji was first in order of execution and, hence was inserted first in the table.
to conform to the same logic, for testing, alter the ChangeSet position and try running the same changelog.mysql.xml.

The above approach is not the best practice and is very error-prone, to deal with this requirement Liquibase provides a runOrder attribute which takes first or last as value and runs ChangeSet accordingly.

runOrder is not supported in formatted SQL changelog.

changelog.mysql.xml

<code class="language-bash">
<?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" runOrder="first">
		<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" runOrder="last">
		<insert catalogName="appledb" tableName="apple">
			<column name="apple_id" />
			<column name="apple_name" value="Fuji" />
			<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="Macintosh" />
			<column name="current_date_time" valueDate="now()" />
		</insert>
	</changeSet>
	<changeSet author="wesome" id="1692599548266-4" runOrder="first">
		<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>

changelog.mysql.yaml

<code class="language-bash">
databaseChangeLog:
  - changeSet:
      id: 1692604842621-1
      author: wesome
      runOrder: first
      changes:
        - createTable:
            catalogName: appledb
            columns:
              - column:
                  autoIncrement: true
                  constraints:
                    nullable: false
                    primaryKey: true
                  name: apple_id
                  type: BIGINT
              - column:
                  name: apple_name
                  type: VARCHAR(255)
              - column:
                  defaultValueComputed: CURRENT_TIMESTAMP
                  name: current_date_time
                  type: datetime
            tableName: apple
  - changeSet:
      id: 1692604842621-2
      author: wesome
      runOrder: last
      changes:
        - insert:
            catalogName: appledb
            columns:
              - column:
                  name: apple_id
                  valueNumeric: 1
              - column:
                  name: apple_name
                  value: Fuji
              - column:
                  name: current_date_time
                  valueDate: now()
            tableName: apple
  - changeSet:
      id: 1692604842621-3
      author: wesome
      changes:
        - insert:
            catalogName: appledb
            columns:
              - column:
                  name: apple_id
                  valueNumeric: 2
              - column:
                  name: apple_name
                  value: Macintosh
              - column:
                  name: current_date_time
                  valueDate: now()
            tableName: apple
  - changeSet:
      id: 1692604842621-4
      author: wesome
      runOrder: first
      changes:
        - insert:
            catalogName: appledb
            columns:
              - column:
                  name: apple_id
                  valueNumeric: 3
              - column:
                  name: apple_name
                  value: Gala
              - column:
                  name: current_date_time
                  valueDate: now()
            tableName: apple

changelog.mysql.json

{
  "databaseChangeLog": [
    {
      "changeSet": {
        "id": "1692604857670-1",
        "author": "wesome",
        "runOrder": "first",
        "changes": [
          {
            "createTable": {
              "catalogName": "appledb",
              "columns": [
                {
                  "column": {
                    "autoIncrement": true,
                    "constraints": {
                      "nullable": false,
                      "primaryKey": true
                    },
                    "name": "apple_id",
                    "type": "BIGINT"
                  }
                },
                {
                  "column": {
                    "name": "apple_name",
                    "type": "VARCHAR(255)"
                  }
                },
                {
                  "column": {
                    "defaultValueComputed": "CURRENT_TIMESTAMP",
                    "name": "current_date_time",
                    "type": "datetime"
                  }
                }
              ],
              "tableName": "apple"
            }
          }
        ]
      }
    },
    {
      "changeSet": {
        "id": "1692604857670-2",
        "author": "wesome",
        "runOrder": "last",
        "changes": [
          {
            "insert": {
              "catalogName": "appledb",
              "columns": [
                {
                  "column": {
                    "name": "apple_id"
                  }
                },
                {
                  "column": {
                    "name": "apple_name",
                    "value": "Fuji"
                  }
                },
                {
                  "column": {
                    "name": "current_date_time",
                    "valueDate": "now()"
                  }
                }
              ],
              "tableName": "apple"
            }
          }
        ]
      }
    },
    {
      "changeSet": {
        "id": "1692604857670-3",
        "author": "wesome",
        "changes": [
          {
            "insert": {
              "catalogName": "appledb",
              "columns": [
                {
                  "column": {
                    "name": "apple_id"
                  }
                },
                {
                  "column": {
                    "name": "apple_name",
                    "value": "Fuji"
                  }
                },
                {
                  "column": {
                    "name": "current_date_time",
                    "valueDate": "now()"
                  }
                }
              ],
              "tableName": "apple"
            }
          }
        ]
      }
    },
    {
      "changeSet": {
        "id": "1692604857670-4",
        "author": "wesome",
        "runOrder": "first",
        "changes": [
          {
            "insert": {
              "catalogName": "appledb",
              "columns": [
                {
                  "column": {
                    "name": "apple_id"
                  }
                },
                {
                  "column": {
                    "name": "apple_name",
                    "value": "Gala"
                  }
                },
                {
                  "column": {
                    "name": "current_date_time",
                    "valueDate": "now()"
                  }
                }
              ],
              "tableName": "apple"
            }
          }
        ]
      }
    }
  ]
}

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

Liquibase prints the ChangeSet execution order in the log as well.

Running Changeset: changelog.mysql.xml::1692599548266-1::wesome
Running Changeset: changelog.mysql.xml::1692599548266-4::wesome
Running Changeset: changelog.mysql.xml::1692599548266-3::wesome
Running Changeset: changelog.mysql.xml::1692599548266-2::wesome

If changelog has create table ChangeSet, then it always should have runOrder="first" other wise, Liquibase migrator will try to run insert ChangeSet and result into table not exist error

follow us on