Liquibase provides the generateChangeLog command to create a ChangeLog file for an existing database. By default, the generateChangeLog command will generate a big ChangeLog file which will have all the tables, functions, views, columns, indexes, foreign keys, primary keys, unique constraints, data, stored procedures, triggers, sequences, etc.
but most development teams try to segregate and manage ChangeLog as per DDL and DML for each table into separate files and include them as per order required.
Straightforward there is no way to generate a separate ChangeLog per table. So the development team first generates ChangeLog for the entire database, and then manually tries to segregate them into separate files. but this approach is error-prone and sometimes creates foreign key voilation. Let's see the same with an example, assume we have database schema as below
create DATABASE IF NOT EXISTS `appledb`;
USE `appledb`;
create TABLE `taste` (
`taste_id` int NOT NULL auto_increment,
`taste` varchar(2000) NOT NULL,
PRIMARY KEY (`taste_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
insert into `taste` (`taste`) VALUES ('sweet'),('sour');
create TABLE `apple` (
`apple_id` bigint NOT NULL auto_increment,
`apple_name` varchar(255) DEFAULT NULL,
`taste_id` int NOT NULL,
PRIMARY KEY (`apple_id`),
KEY `FKqg39etajdct3xxd813arauyit` (`taste_id`),
CONSTRAINT `taste_id_taste_fk` FOREIGN KEY (`taste_id`) REFERENCES `taste` (`taste_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
insert into `apple` (`apple_name`, `taste_id` ) VALUES ('Macintosh',1),('Fuji',2);
commit;Run the above SQL, and create a database and tables with respective values. once done, let's generate a ChangeLog for the above data with the help of Liquibase.
liquibase.properties
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
execute the command liquibase generateChangeLog it will generate a changelog.mysql.xml file for the entire database.
Manually segrigating the generated ChangeLog file is very error-prone.
Generate ChangeLog for each sequence, table and data individually
As stated above, so far there has been no straightforward solution for this problem from Liquiabse, but there are some workarounds.
Liquibase provides diffTypes tag, which will only generate the database object if passed, below are the available diffTypes
| diffType | default | description | |
| 1 | tables | yes | will generate the table creation ChangeLog only |
| 2 | columns | yes | will generate column addition ChangeLog only |
| 3 | views | yes | will generate views creations ChangeLog only |
| 4 | primaryKeys | yes | will generate primary Keys ChangeLog only |
| 5 | indexes | yes | will generate indexes ChangeLog only |
| 6 | foreignKeys | yes | will generate foreign keys ChangeLog only |
| 7 | sequences | yes | will generate sequences ChangeLog only |
| 8 | data | no | will generate insert data ChangeLog only |
If No diffTypes is mentioned then all the default diffTypes will be considered
Liquibase provides another includeObjects tag, which takes table and sequence.
By combining diffTypes and includeObjects as per requirement, we can achieve the desired ChangeLog file at a time, which will be renamed and another ChangeLog will be generated, let's see this with an example.
Assume we are working with the same SQL as used above
create DATABASE IF NOT EXISTS `appledb`;
USE `appledb`;
create TABLE `taste` (
`taste_id` int NOT NULL auto_increment,
`taste` varchar(2000) NOT NULL,
PRIMARY KEY (`taste_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
insert into `taste` (`taste`) VALUES ('sweet'),('sour');
create TABLE `apple` (
`apple_id` bigint NOT NULL auto_increment,
`apple_name` varchar(255) DEFAULT NULL,
`taste_id` int NOT NULL,
PRIMARY KEY (`apple_id`),
KEY `FKqg39etajdct3xxd813arauyit` (`taste_id`),
CONSTRAINT `taste_id_taste_fk` FOREIGN KEY (`taste_id`) REFERENCES `taste` (`taste_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
insert into `apple` (`apple_name`, `taste_id` ) VALUES ('Macintosh',1),('Fuji',2);
commit;Run the above SQL, and create a database and tables with respective values. once done, let's generate a ChangeLog for the above data with the help of Liquibase.
Generate Taste Table Creation ChangeLog
Let's modify the Liquibase.properties as below and generate a ChangeLog for the taste table creation changeset.
liquibase.properties
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
overwriteOutputFile=true
includeTablespace:true
includeCatalog:true
includeObjects=table:tasteExecute the command liquibase generateChangeLog it will generate a changelog.mysql.xml file which will contain create taste table changeset only, rename this file to changelog.mysql.create.taste.xml
Generate Taste Table Insertion ChangeLog
modify the liquibase.properties as below and generate a ChangeLog for the taste table insertion changeset.
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
overwriteOutputFile=true
includeTablespace:true
includeCatalog:true
diffTypes:data
includeObjects=table:tasteExecute the command liquibase generateChangeLog it will generate a changelog.mysql.xml file which will contain insert taste table changeset only, rename this file to changelog.mysql.insert.taste.xml
Generate Apple Table Creation ChangeLog
modify the liquibase.properties as below and generate a ChangeLog for the apple table creation changeset.
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
overwriteOutputFile=true
includeTablespace:true
includeCatalog:true
includeObjects=table:appleExecute the command liquibase generateChangeLog it will generate a changelog.mysql.xml file which will contain the create apple table changeset only, rename this file to changelog.mysql.insert.taste.xml
Generate Apple Table Insertion ChangeLog
modify the liquibase.properties as below and generate a ChangeLog for the apple table insertion changeset.
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
overwriteOutputFile=true
includeTablespace:true
includeCatalog:true
includeObjects=table:appleExecute the command liquibase generateChangeLog it will generate a changelog.mysql.xml file which will contain insert apple table changeset only, rename this file to changelog.mysql.insert.apple.xml
Create Master ChangeLog and include all Individual ChangeLog
Now let's create a master changelog.mysql.xml file, which will include all the ChangeLog we have just created it in the required sequence.
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" objectQuotingStrategy="QUOTE_ALL_OBJECTS">
<include file="changelog.mysql.create.taste.xml" />
<include file="changelog.mysql.insert.taste.xml" />
<include file="changelog.mysql.create.apple.xml" />
<include file="changelog.mysql.insert.apple.xml" />
</databaseChangeLog>liquibase.properties
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: rootrootchangelog.mysql.create.taste.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="shriksha (generated)" id="1696659398982-1">
<createTable catalogName="appledb" tableName="taste">
<column autoIncrement="true" name="taste_id" type="INT">
<constraints nullable="false" primaryKey="true" />
</column>
<column name="taste" type="VARCHAR(2000)">
<constraints nullable="false" />
</column>
</createTable>
</changeSet>
</databaseChangeLog>changelog.mysql.insert.taste.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="shriksha (generated)" id="1696659621108-1">
<insert catalogName="appledb" tableName="taste">
<column name="taste_id" valueNumeric="1"/>
<column name="taste" value="sweet"/>
</insert>
<insert catalogName="appledb" tableName="taste">
<column name="taste_id" valueNumeric="2"/>
<column name="taste" value="sour"/>
</insert>
</changeSet>
</databaseChangeLog>changelog.mysql.create.apple.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="shriksha (generated)" id="1696659529449-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 name="taste_id" type="INT">
<constraints nullable="false" />
</column>
</createTable>
</changeSet>
<changeSet author="shriksha (generated)" id="1696659529449-2">
<createIndex catalogName="appledb" indexName="FKqg39etajdct3xxd813arauyit" tableName="apple">
<column name="taste_id" />
</createIndex>
</changeSet>
<changeSet author="shriksha (generated)" id="1696659529449-3">
<addForeignKeyConstraint baseColumnNames="taste_id" baseTableCatalogName="appledb" baseTableName="apple" constraintName="taste_id_taste_fk" deferrable="false" initiallyDeferred="false" onDelete="RESTRICT" onUpdate="RESTRICT" referencedColumnNames="taste_id" referencedTableCatalogName="appledb" referencedTableName="taste" validate="true" />
</changeSet>
</databaseChangeLog>changelog.mysql.insert.apple.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="shriksha (generated)" id="1696659833557-1">
<insert catalogName="appledb" tableName="apple">
<column name="apple_id" valueNumeric="1"/>
<column name="apple_name" value="Macintosh"/>
<column name="taste_id" valueNumeric="1"/>
</insert>
<insert catalogName="appledb" tableName="apple">
<column name="apple_id" valueNumeric="2"/>
<column name="apple_name" value="Fuji"/>
<column name="taste_id" valueNumeric="2"/>
</insert>
</changeSet>
</databaseChangeLog>execute the command liquibase update, it will create and insert records in tables as per the below order
- create taste table
- insert record in taste table
- create apple table
- insert record in apple table
The same can be verified by running command
select * from appledb.apple ap, appledb.taste ta where ap.taste_id=ta.taste_id;