Liquibase is a tool for managing and executing database changes.
—
This document covers Liquibase's changelog and changeset management system, including changelog parsing, changeset definition, and change types.
import liquibase.changelog.DatabaseChangeLog;
import liquibase.changelog.ChangeSet;
import liquibase.changelog.ChangeLogParameters;
import liquibase.change.Change;
// Core change types
import liquibase.change.core.*;
// Context and label filtering
import liquibase.Contexts;
import liquibase.Labels;
import liquibase.LabelExpression;
// Validation
import liquibase.exception.ValidationErrors;
import liquibase.exception.LiquibaseException;
// Database
import liquibase.database.Database;
import java.util.List;
import java.util.Set;The DatabaseChangeLog represents a complete changelog containing multiple changesets.
/**
* Get the physical file path of the changelog
* @return Physical file path
*/
public String getPhysicalFilePath()
/**
* Set the physical file path
* @param physicalFilePath Physical path to the changelog file
*/
public void setPhysicalFilePath(String physicalFilePath)
/**
* Get the logical file path used for includes
* @return Logical file path
*/
public String getLogicalFilePath()
/**
* Set the logical file path for includes
* @param logicalFilePath Logical path for changelog references
*/
public void setLogicalFilePath(String logicalFilePath)/**
* Get all changesets in the changelog
* @return List of all changesets
*/
public List<ChangeSet> getChangeSets()
/**
* Add a changeset to the changelog
* @param changeSet ChangeSet to add
*/
public void addChangeSet(ChangeSet changeSet)
/**
* Find specific changeset by identifiers
* @param path File path
* @param author Changeset author
* @param id Changeset ID
* @return ChangeSet if found, null otherwise
*/
public ChangeSet getChangeSet(String path, String author, String id)/**
* Validate changelog against database
* @param database Target database
* @param contexts Execution contexts for filtering
* @param labelExpression Label expression for filtering
* @throws LiquibaseException if validation fails
*/
public void validate(Database database, Contexts contexts, LabelExpression labelExpression) throws LiquibaseException
/**
* Validate multiple changelogs
* @param database Target database
* @param changeLogsToValidate Changelogs to validate
* @return ValidationErrors containing any validation issues
*/
public ValidationErrors validate(Database database, DatabaseChangeLog... changeLogsToValidate)/**
* Get changelog parameters
* @return ChangeLogParameters instance
*/
public ChangeLogParameters getChangeLogParameters()
/**
* Set changelog parameters
* @param changeLogParameters Parameters to set
*/
public void setChangeLogParameters(ChangeLogParameters changeLogParameters)The ChangeSet represents a single changeset containing one or more changes.
/**
* Get unique changeset ID
* @return Changeset ID
*/
public String getId()
/**
* Get changeset author
* @return Author name
*/
public String getAuthor()
/**
* Get file path containing this changeset
* @return File path
*/
public String getFilePath()/**
* Get execution contexts for this changeset
* @return Contexts object
*/
public Contexts getContexts()
/**
* Get execution labels for this changeset
* @return Labels object
*/
public Labels getLabels()
/**
* Get target database types for this changeset
* @return Set of database type names
*/
public Set<String> getDbms()
/**
* Check if changeset should re-run when changed
* @return true if runOnChange is enabled
*/
public Boolean getRunOnChange()
/**
* Check if changeset should always run
* @return true if runAlways is enabled
*/
public Boolean getRunAlways()
/**
* Check if changeset should fail on error
* @return true if failOnError is enabled (default)
*/
public Boolean getFailOnError()/**
* Get list of changes in this changeset
* @return List of Change objects
*/
public List<Change> getChanges()
/**
* Add a change to this changeset
* @param change Change to add
*/
public void addChange(Change change)/**
* Get rollback changes for this changeset
* @return List of rollback changes
*/
public List<Change> getRollback()
/**
* Add a rollback change
* @param change Rollback change to add
*/
public void addRollbackChange(Change change)Create, modify, and drop tables:
// Create table
public class CreateTableChange extends AbstractChange {
public void setTableName(String tableName)
public void setSchemaName(String schemaName)
public void setCatalogName(String catalogName)
public void addColumn(ColumnConfig column)
}
// Drop table
public class DropTableChange extends AbstractChange {
public void setTableName(String tableName)
public void setSchemaName(String schemaName)
public void setCatalogName(String catalogName)
public void setCascadeConstraints(Boolean cascadeConstraints)
}
// Rename table
public class RenameTableChange extends AbstractChange {
public void setOldTableName(String oldTableName)
public void setNewTableName(String newTableName)
public void setSchemaName(String schemaName)
public void setCatalogName(String catalogName)
}Add, modify, and drop columns:
// Add column
public class AddColumnChange extends AbstractChange {
public void setTableName(String tableName)
public void setSchemaName(String schemaName)
public void addColumn(ColumnConfig column)
}
// Drop column
public class DropColumnChange extends AbstractChange {
public void setTableName(String tableName)
public void setColumnName(String columnName)
public void setSchemaName(String schemaName)
}
// Modify data type
public class ModifyDataTypeChange extends AbstractChange {
public void setTableName(String tableName)
public void setColumnName(String columnName)
public void setNewDataType(String newDataType)
public void setSchemaName(String schemaName)
}
// Rename column
public class RenameColumnChange extends AbstractChange {
public void setTableName(String tableName)
public void setOldColumnName(String oldColumnName)
public void setNewColumnName(String newColumnName)
public void setColumnDataType(String columnDataType)
public void setSchemaName(String schemaName)
}Manage various database constraints:
// Add primary key
public class AddPrimaryKeyChange extends AbstractChange {
public void setTableName(String tableName)
public void setColumnNames(String columnNames)
public void setConstraintName(String constraintName)
public void setSchemaName(String schemaName)
}
// Drop primary key
public class DropPrimaryKeyChange extends AbstractChange {
public void setTableName(String tableName)
public void setConstraintName(String constraintName)
public void setSchemaName(String schemaName)
}
// Add foreign key
public class AddForeignKeyConstraintChange extends AbstractChange {
public void setBaseTableName(String baseTableName)
public void setBaseColumnNames(String baseColumnNames)
public void setReferencedTableName(String referencedTableName)
public void setReferencedColumnNames(String referencedColumnNames)
public void setConstraintName(String constraintName)
public void setOnDelete(String onDelete)
public void setOnUpdate(String onUpdate)
}
// Drop foreign key
public class DropForeignKeyConstraintChange extends AbstractChange {
public void setBaseTableName(String baseTableName)
public void setConstraintName(String constraintName)
public void setBaseTableSchemaName(String baseTableSchemaName)
}
// Add unique constraint
public class AddUniqueConstraintChange extends AbstractChange {
public void setTableName(String tableName)
public void setColumnNames(String columnNames)
public void setConstraintName(String constraintName)
public void setSchemaName(String schemaName)
}
// Drop unique constraint
public class DropUniqueConstraintChange extends AbstractChange {
public void setTableName(String tableName)
public void setConstraintName(String constraintName)
public void setSchemaName(String schemaName)
}
// Add not null constraint
public class AddNotNullConstraintChange extends AbstractChange {
public void setTableName(String tableName)
public void setColumnName(String columnName)
public void setColumnDataType(String columnDataType)
public void setDefaultNullValue(String defaultNullValue)
public void setSchemaName(String schemaName)
}
// Drop not null constraint
public class DropNotNullConstraintChange extends AbstractChange {
public void setTableName(String tableName)
public void setColumnName(String columnName)
public void setColumnDataType(String columnDataType)
public void setSchemaName(String schemaName)
}Create and drop database indexes:
// Create index
public class CreateIndexChange extends AbstractChange {
public void setTableName(String tableName)
public void setIndexName(String indexName)
public void addColumn(ColumnConfig column)
public void setUnique(Boolean unique)
public void setSchemaName(String schemaName)
}
// Drop index
public class DropIndexChange extends AbstractChange {
public void setTableName(String tableName)
public void setIndexName(String indexName)
public void setSchemaName(String schemaName)
}Manipulate table data:
// Insert data
public class InsertDataChange extends AbstractChange {
public void setTableName(String tableName)
public void addColumn(ColumnConfig column)
public void setSchemaName(String schemaName)
}
// Update data
public class UpdateDataChange extends AbstractChange {
public void setTableName(String tableName)
public void addColumn(ColumnConfig column)
public void addWhereParam(ColumnConfig whereParam)
public void setWhere(String where)
public void setSchemaName(String schemaName)
}
// Delete data
public class DeleteDataChange extends AbstractChange {
public void setTableName(String tableName)
public void addWhereParam(ColumnConfig whereParam)
public void setWhere(String where)
public void setSchemaName(String schemaName)
}
// Load data from file
public class LoadDataChange extends AbstractChange {
public void setTableName(String tableName)
public void setFile(String file)
public void setRelativeToChangelogFile(Boolean relativeToChangelogFile)
public void setEncoding(String encoding)
public void setSeparator(String separator)
public void setQuotchar(String quotchar)
public void addColumn(LoadDataColumnConfig column)
}
// Load and update data
public class LoadUpdateDataChange extends AbstractChange {
public void setTableName(String tableName)
public void setFile(String file)
public void setPrimaryKey(String primaryKey)
public void addColumn(LoadDataColumnConfig column)
}Manage views and stored procedures:
// Create view
public class CreateViewChange extends AbstractChange {
public void setViewName(String viewName)
public void setSelectQuery(String selectQuery)
public void setSchemaName(String schemaName)
public void setReplaceIfExists(Boolean replaceIfExists)
}
// Drop view
public class DropViewChange extends AbstractChange {
public void setViewName(String viewName)
public void setSchemaName(String schemaName)
}
// Create stored procedure
public class CreateProcedureChange extends AbstractChange {
public void setProcedureName(String procedureName)
public void setProcedureText(String procedureText)
public void setSchemaName(String schemaName)
}
// Drop stored procedure
public class DropProcedureChange extends AbstractChange {
public void setProcedureName(String procedureName)
public void setSchemaName(String schemaName)
}Execute custom SQL:
// Execute raw SQL
public class SQLChange extends AbstractChange {
public void setSql(String sql)
public void setEndDelimiter(String endDelimiter)
public void setSplitStatements(Boolean splitStatements)
public void setStripComments(Boolean stripComments)
}
// Execute SQL from file
public class SQLFileChange extends AbstractChange {
public void setPath(String path)
public void setRelativeToChangelogFile(Boolean relativeToChangelogFile)
public void setEncoding(String encoding)
public void setEndDelimiter(String endDelimiter)
public void setSplitStatements(Boolean splitStatements)
}import liquibase.changelog.DatabaseChangeLog;
import liquibase.changelog.ChangeSet;
import liquibase.change.core.CreateTableChange;
import liquibase.change.ColumnConfig;
// Create changelog
DatabaseChangeLog changelog = new DatabaseChangeLog();
changelog.setPhysicalFilePath("db/changelog/programmatic-changelog.xml");
// Create changeset
ChangeSet changeSet = new ChangeSet(
"1", // id
"admin", // author
false, // alwaysRun
false, // runOnChange
"db/changelog/programmatic-changelog.xml", // filePath
null, // contextFilter
null, // dbmsList
null, // labels
true, // runInTransaction
null, // objectQuotingStrategy
changelog // changeLog
);
// Create table change
CreateTableChange createTable = new CreateTableChange();
createTable.setTableName("users");
createTable.setSchemaName("public");
// Add columns
ColumnConfig idColumn = new ColumnConfig();
idColumn.setName("id");
idColumn.setType("BIGINT");
idColumn.setAutoIncrement(true);
ColumnConfig constraints = new ColumnConfig.ConstraintsConfig();
constraints.setPrimaryKey(true);
constraints.setNullable(false);
idColumn.setConstraints(constraints);
createTable.addColumn(idColumn);
ColumnConfig nameColumn = new ColumnConfig();
nameColumn.setName("name");
nameColumn.setType("VARCHAR(255)");
ColumnConfig nameConstraints = new ColumnConfig.ConstraintsConfig();
nameConstraints.setNullable(false);
nameColumn.setConstraints(nameConstraints);
createTable.addColumn(nameColumn);
ColumnConfig emailColumn = new ColumnConfig();
emailColumn.setName("email");
emailColumn.setType("VARCHAR(255)");
ColumnConfig emailConstraints = new ColumnConfig.ConstraintsConfig();
emailConstraints.setUnique(true);
emailColumn.setConstraints(emailConstraints);
createTable.addColumn(emailColumn);
// Add change to changeset
changeSet.addChange(createTable);
// Add changeset to changelog
changelog.addChangeSet(changeSet);// Create comprehensive changeset
ChangeSet complexChangeSet = new ChangeSet(
"2", "admin", false, false,
"db/changelog/complex-changes.xml",
null, null, null, true, null, changelog
);
// Add table
CreateTableChange createOrdersTable = new CreateTableChange();
createOrdersTable.setTableName("orders");
createOrdersTable.setSchemaName("public");
ColumnConfig orderIdColumn = new ColumnConfig();
orderIdColumn.setName("order_id");
orderIdColumn.setType("BIGINT");
orderIdColumn.setAutoIncrement(true);
ColumnConfig orderIdConstraints = new ColumnConfig.ConstraintsConfig();
orderIdConstraints.setPrimaryKey(true);
orderIdColumn.setConstraints(orderIdConstraints);
createOrdersTable.addColumn(orderIdColumn);
ColumnConfig userIdColumn = new ColumnConfig();
userIdColumn.setName("user_id");
userIdColumn.setType("BIGINT");
ColumnConfig userIdConstraints = new ColumnConfig.ConstraintsConfig();
userIdConstraints.setNullable(false);
userIdColumn.setConstraints(userIdConstraints);
createOrdersTable.addColumn(userIdColumn);
complexChangeSet.addChange(createOrdersTable);
// Add foreign key
AddForeignKeyConstraintChange addFK = new AddForeignKeyConstraintChange();
addFK.setBaseTableName("orders");
addFK.setBaseColumnNames("user_id");
addFK.setReferencedTableName("users");
addFK.setReferencedColumnNames("id");
addFK.setConstraintName("fk_orders_user_id");
addFK.setOnDelete("CASCADE");
complexChangeSet.addChange(addFK);
// Add index
CreateIndexChange createIndex = new CreateIndexChange();
createIndex.setTableName("orders");
createIndex.setIndexName("idx_orders_user_id");
ColumnConfig indexColumn = new ColumnConfig();
indexColumn.setName("user_id");
createIndex.addColumn(indexColumn);
complexChangeSet.addChange(createIndex);
// Insert sample data
InsertDataChange insertData = new InsertDataChange();
insertData.setTableName("users");
ColumnConfig nameData = new ColumnConfig();
nameData.setName("name");
nameData.setValue("John Doe");
insertData.addColumn(nameData);
ColumnConfig emailData = new ColumnConfig();
emailData.setName("email");
emailData.setValue("john.doe@example.com");
insertData.addColumn(emailData);
complexChangeSet.addChange(insertData);
changelog.addChangeSet(complexChangeSet);// Create changeset with filtering
ChangeSet filteredChangeSet = new ChangeSet(
"3", "developer", false, false,
"db/changelog/dev-changes.xml",
"development,testing", // contexts
null, // dbms
"feature-auth,version-2.0", // labels
true, null, changelog
);
// Add development-specific change
CreateTableChange devTable = new CreateTableChange();
devTable.setTableName("debug_log");
devTable.setSchemaName("public");
ColumnConfig logIdColumn = new ColumnConfig();
logIdColumn.setName("log_id");
logIdColumn.setType("BIGINT");
logIdColumn.setAutoIncrement(true);
ColumnConfig logIdConstraints = new ColumnConfig.ConstraintsConfig();
logIdConstraints.setPrimaryKey(true);
logIdColumn.setConstraints(logIdConstraints);
devTable.addColumn(logIdColumn);
ColumnConfig messageColumn = new ColumnConfig();
messageColumn.setName("message");
messageColumn.setType("TEXT");
devTable.addColumn(messageColumn);
filteredChangeSet.addChange(devTable);
changelog.addChangeSet(filteredChangeSet);// Create changeset with custom SQL
ChangeSet sqlChangeSet = new ChangeSet(
"4", "dba", false, false,
"db/changelog/custom-sql.xml",
null, null, null, true, null, changelog
);
// Add custom SQL change
SQLChange customSQL = new SQLChange();
customSQL.setSql(
"CREATE OR REPLACE FUNCTION calculate_order_total(order_id BIGINT) " +
"RETURNS DECIMAL(10,2) AS $$ " +
"BEGIN " +
" RETURN (SELECT SUM(quantity * price) FROM order_items WHERE order_id = $1); " +
"END; " +
"$$ LANGUAGE plpgsql;"
);
customSQL.setEndDelimiter(";");
customSQL.setSplitStatements(false);
sqlChangeSet.addChange(customSQL);
// Add rollback SQL
SQLChange rollbackSQL = new SQLChange();
rollbackSQL.setSql("DROP FUNCTION IF EXISTS calculate_order_total(BIGINT);");
sqlChangeSet.addRollbackChange(rollbackSQL);
changelog.addChangeSet(sqlChangeSet);import liquibase.database.Database;
import liquibase.Contexts;
import liquibase.LabelExpression;
import liquibase.exception.ValidationErrors;
// Validate changelog
try {
changelog.validate(database, new Contexts("production"), new LabelExpression());
System.out.println("Changelog validation passed");
} catch (LiquibaseException e) {
System.err.println("Changelog validation failed: " + e.getMessage());
}
// Detailed validation
ValidationErrors errors = changelog.validate(database);
if (errors.hasErrors()) {
System.out.println("Validation errors found:");
for (String error : errors.getErrorMessages()) {
System.out.println(" - " + error);
}
}Install with Tessl CLI
npx tessl i tessl/maven-org-liquibase--liquibase-core