changeset

The changeset tag is what you use to group database Change Types together and is a unit of change that Liquibase executes on a database. A list of changes created by multiple changesets are tracked in a changelog.

A changeset is uniquely tagged by both an author and an id attribute (author:id), as well as the changelog file path. The id tag is only used as an identifier, it does not direct the order that changes are run and does not even have to be an integer. If you do not know or do not wish to save the actual author, simply use a placeholder value such as UNKNOWN. Both author and id must be included to execute the changeset.

<?xml version="1.0" encoding="UTF-8"?>  

<databaseChangeLog  
  xmlns="http://www.liquibase.org/xml/ns/dbchangelog"  
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
  xmlns:pro="http://www.liquibase.org/xml/ns/pro"  
  xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.8.xsd
      http://www.liquibase.org/xml/ns/pro http://www.liquibase.org/xml/ns/pro/liquibase-pro-3.8.xsd">  
    <changeSet  id="1"  author="bob">  
        <comment>A sample change log</comment>  
        <createTable/>  
    </changeSet>  
    <changeSet  id="2"  author="bob"  runAlways="true">  
        <alterTable/>  
    </changeSet>  
    <changeSet  id="3"  author="alice"  failOnError="false"  dbms="oracle">  
        <alterTable/>  
    </changeSet>  
    <changeSet  id="4"  author="alice"  failOnError="false"  dbms="!oracle">  
        <alterTable/>  
    </changeSet>  

</databaseChangeLog>

As Liquibase executes the DATABASECHANGELOG, it reads the changesets in order and, for each one, checks the DATABASECHANGELOG table to see if the combination of id/author/filepath has been run. If it has been run, the changeset will be skipped unless there is a true “runAlways” tag. After all the changes in the changesets are run, Liquibase will insert a new row with the id/author/filepath along with an MD5Sum of the changeset (see below) in the DATABASECHANGELOG.

Note: filepath is the path how the changeLogFile parameter is defined. Even if the same file is referenced with a different path, that is considered a different file unless the logicalFilePath is defined.

Liquibase attempts to execute each changeset in a transaction that is committed at the end, or rolled back if there is an error. Some databases will auto-commit statements which interferes with this transaction setup and could lead to an unexpected database state. Therefore, it is usually best to have just one change per changeset unless there is a group of non-auto-committing changes that you want applied as a transaction such as inserting data.

Available attributes

id An alpha-numeric identifier required
author The creator of the changeset required
dbms The type of a database which that changeset is to be used for. When the migration step is running, it checks the database type against this attribute. Valid database type names are listed on the supported databases page. It is possible to list multiple databases separated by commas. You can also specify that a changeset is NOT applicable to a particular database type by prefixing with !. The keywords all and none are also available.
runAlways Executes the changeset on every run, even if it has been run before
runOnChange Executes the change the first time it is seen and each time the change set has been changed
Contexts Controls whether a changeset is executed, depending on runtime settings. Any string can be used for the context name and they are checked case-insensitively.
Labels Controls whether a changeset is executed, depending on runtime settings. Any string can be used for the label name and they are checked case-insensitively.
runInTransaction Should the changeset be ran as a single transaction (if possible)? Defaults to true. Warning: be careful with this attribute. If set to false and an error occurs part way through running a changeset containing multiple statements, the LiquibaseDATABASECHANGELOG table will be left in an invalid state. Since 1.9
failOnError Should the migration fail if an error occurs while executing the changeset? Default=true
objectQuotingStrategy This controls how object names are quoted in the SQL generated or used in calls to the database. Different databases do different things to the names of objects, for example Oracle converts everything to uppercase (unless quoted). There are three possible values. The default value is LEGACY.
LEGACY - Same behavior as in Liquibase 2.0
QUOTE_ALL_OBJECTS - Every object gets quoted. e.g. person becomes "person".
QUOTE_ONLY_RESERVED_WORDS - Quote reserved keywords and invalid column names.
runOrder Since 3.5
created Since 3.5
ignore Ignore the changeset from the executionSince 3.6
logicalFilePath Use to override the file name and path when creating the unique identifier of changesets. Required when moving or renaming change logs.

Available sub-tags

comment A description of the changeset. XML comments will provide the same benefit, future releases of Liquibase may be able to make use of <comment> tag comments to generate documentation
preConditions Preconditions that must pass before the change set will be executed. Useful for doing a data sanity check before doing something unrecoverable such as a dropTable Since 1.7
<Any Refactoring Tag(s)> The database change(s) to run as part of this changeset (so called Change Types).
validCheckSum Add a checksum that is considered valid for this changeset, regardless of what is stored in the database. Used primarily when you need to change a changeset and don't want errors thrown on databases on which it has already run (not a recommended procedure). Special value "1:any" will match to any checksum and not execute the changeset on ANY changeSince 1.7
rollback SQL statements or Change Type tags that describe how to rollback the changeset. See Liquibase Rollback Workflow.

Rollback tag

The rollback tag describes how to roll back a change using SQL statement(s), change tags, or a reference to a previous changeset.

Rollback tag examples

Here we see that you can just have plain SQL in the content part of the <rollback> element. The text in the element is treated as a <sql> change with stripComments set to true, splitStatements set to true and endDelimiter set to ;.

<changeSet  id="1"  author="bob">  
    <createTable  tableName="testTable">  
    <rollback>
        drop table testTable
    </rollback>  
</changeSet>

Here we see that you can have any type of change in the <rollback> element.

<changeSet  id="1"  author="bob">  
    <createTable  tableName="testTable">  
    <rollback>  
        <dropTable  tableName="testTable"/>  
    </rollback>  
</changeSet>

This example shows how a <rollback> element can refer to another changeset. This would be interpreted as “In order to roll back this changeset (id=”2”), apply the changeset with id=1”

<changeSet  id="2"  author="bob">  
    <dropTable  tableName="testTable"/>  
    <rollback  changeSetId="1"  changeSetAuthor="bob"/>  
</changeSet>

changeset check sums

When Liquibase reaches a changeset, it computes a check sum and stores it in the DATABASECHANGELOG. The value of storing the checksum is so that Liquibase can know if someone changed the changes in the changeset since it was run. If the changeset was changed since it was run, Liquibase will exit the migration with an error message like Validation failed: change set check sums <changeset identifer> was: <old checksum> but is now: <newchecksum>. This is because Liquibase cannot know what was changed and the database may be in a state different than what the changelog is expecting. If there was a valid reason for the changeset to have been changed and you want to ignore this error, you have two options.

The first option is to manually update the DATABASECHANGELOG table so that the row with the corresponding id/author/filepath has a null value for the check sum. You would need to do this for all environments where the changeset has been deployed. The next time you run the Liquibase update command, it will update the check sum value to the new correct value.

The second option is to add a <validCheckSum> element to the changeset. The text contents of the element should be the “old” checksum from the error message.

Check sums are also used in conjunction with the “runOnChange” changeset attribute. There are times you may not want to add a new changeset because you only need to know about the current version, but you want this change applied whenever it is updated. A good example of when you would want this is stored procedures. If you copy the entire text of the stored procedure to a new changeset each time you make a change you will not only end up with a very long changelog, but you will lose the merging and diff-ing power of your source control. Instead, put the text of the stored procedure in a changeset with a runOnChange=”true” attribute. The stored procedure will be re-created when and only when there is a change to the text of it.

Related Links