Keep your changelogs organized
The most common way we see changelogs organized is by major release. Choose a package in your classpath to store the changelogs, preferably near your database access classes. In this example, we will use com/example/db/changelog.
com example db changelog db.changelog-master.xml db.changelog-1.0.xml db.changelog-1.1.xml db.changelog-2.0.xml DatabasePool.java AbstractDAO.java
The master.xml includes the changelog for the releases in the correct order. In the example above it could look like this:
<?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" xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.8.xsd"> <include file="com/example/db/changelog/db.changelog-1.0.xml"/> <include file="com/example/db/changelog/db.changelog-1.1.xml"/> <include file="com/example/db/changelog/db.changelog-2.0.xml"/> </databaseChangeLog>
Each of the included XML files needs to be in the same format as a standard XML database changelog, something like this:
<?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" xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.8.xsd"> <changeSet author="authorName" id="changelog-1.0"> <createTable tableName="TablesAndTables"> <column name="COLUMN1" type="TEXT"> <constraints nullable="true" primaryKey="false" unique="false"/> </column> </createTable> </changeSet> </databaseChangeLog>
The db.changelog-master.xml is the changelog you pass to all Liquibase calls.
Manage Stored Procedures
Try to maintain separate changelog for Stored Procedures and use runOnChange=”true”. This flag forces Liquibase to check if the changeset was modified. If so, Liquibase executes the change again.
Keep it to one change per changeset
Avoid multiple changes per changeset so you can avoid failed auto-commit statements that can leave the database in an unexpected state.
Choosing changeset IDs
Choose a changeset ID that works for you. Some use a number sequence starting from 1 and unique within the changelog. Others choose a descriptive name (e.g., ‘new-address-table’).
Always use <comments> in the changesets. As they say, “A stitch in time saves nine!”
Always have a rollback plan
Write changesets in a way that they can be rolled back. For example, use a relevant change clause instead of using a custom <sql> tag. Include a <rollback> clause whenever a change doesn’t support an out-of-box rollback. (e.g., <sql>, <insert>, etc). Learn more about rollbacks.
Manage your reference data
Leverage Liquibase to manage your reference data. Environment separation (DEV, QA, PROD) can be achieved using contexts. Learn about Liquibase contexts.
Typical procedure for the developer
- Using your favorite IDE or editor, create a new local changeset containing the change
- Run Liquibase to execute the new changeset (this tests the SQL code)
- Perform the corresponding changes in the application code (e.g., Java code)
- Test the new application code together with the database change
- Commit both the changeset and the application code
Using Liquibase to achieve CI/CD for databases
Database schema migrations are an essential task for every software project. Learn how to integrate Liquibase into your process to achieve CI/CD for databases.
Consider advanced Liquibase features and support
Advanced features and support designed for teams of all sizes is available via Liquibase.com.