Running Liquibase change sets — Part 1: command line
After a brief introduction into Liquibase I continue the topic with using this framework.
There are many options to use Liquibase, I’ll show you some (command line, maven and Java execution) but feel free to look at the website of the tool to get a more detailed documentation of the usages.
Using a properties file
What are properties files? And why do we need them?
As you may know already properties files contain diverse properties for a specific application — and naturally the application has to be able to manage those properties. Liquibase is capable for handling properties files. And why do we need them? To gather all changing variables into one file, one point to edit. And besides this it helps you configure this database framework. How?
Imagine, you have to start your updates from the console:
java -jar liquibase.jar --driver=org.h2.Driver --classpath=h2-1.3.170.jar --changeLogFile=variations/src/main/resources/dbchange/master.xml --url=jdbc:h2:D:/Variaciok/db/variation --username=sa --password= update
It is not very pleasant, is it? Every time you call the jar, you have to add the DB URL, username, password, driver, changeset file(s)… This is really a no-go. This is where we can use properties files.
What is in such a file? Well, all your start arguments like dirver, changelog file, username, password, DB URL… And of course: paths are relative to the execution folder.
driver: org.h2.Driver classpath: h2-1.3.170.jar changeLogFile: variations/src/main/resources/dbchange/master.xml url: jdbc:h2:D:/db/variation username: sa password:
We could name the file as we like. But if we give it the name “liquibase.properies” then it could be a bit of help when using the console for starting Liquibase…
Line 3 represents a common way to bunch changesets together: you define in your main ChangeSet folder a master.xml and there you add all release XMLs which you want to get executed. This seems a bit overhead (making folders for each release, define a bundle for this release and then define another bundle for these bundles) but with a long living project this could make sense.
For example you have a satisfying release and you think your DB Schema is as good as it can be (with your arounc 100 changesets). So in this case you can do a rebase of the database, and so you have only one changeset with every actual existing table and sequence — so you can use only this one changeset (which should be more cleaner than the sequence of the previous changes) and execute it on the newly deployed servers.
And with the releasechanges.xml in your release folder you can manage the sequence of the change-execution.
Console / Command Line
This is the simplest way to execute your liquibase changes. Just open a console / command line and enter the following command (I assume we are in our working directory where the liquibase.jar is located):
java -jar liquibase.jar –defaultsFile=our_database.properties update
If we named the properies file “liquibase.properties” and it is in the same folder than our liquibase.jar then we could simplify the execution and leave the filename:
java -jar liquibase.jar update
A short look at the database
After executing the changeset (or migration as it is called in the liquibase jargon) it’s a good idea to look at the database and see if our tables are created or not.
Well, our tables are there — but there two additional tables we did not add to our changeset: DATABASECHANGELOG and DATABASECHANGELOGLOCK.
These are two tables from Liquibase which manage the changes over time. The DatabaseChangeLogLock is a simple table “locking” the database if one execution of liquibase is already running. If you start one migration and another on the same database, the second one waits until it gets the lock.
The DatabaseChangeLog table contains every executed change set with ID, author, execution timestamp, MD5 sum, Liquibase version — just to mention a few.
About the MD5 checksum
Each file which is successfully imported (or ran) by Liquibase gets it’s MD5 checksum stored in the database for two purposes:
Rerunability means, that you can use this checksum with the “runOnChange=true” changeset property which tells liquibase it should re-run the changeset if it has changed.
And if you do not use the above mentioned property, liquibase throws an exception if the has been changed since its run. So it is a safety measure to prevent unwanted changes in the database.
And failures in one changeset cause that liquibase stops working — this means if you have 10 changesets defined to be executed and #3 throws an exception (changed MD5 checksum, SQL Exception or anything) the other changes (#4–#10) will not be executed. Be careful. I’d suggest, you have a proper error handling in your application which does not let you start the application if there is a Liquibase error.
It is eventually important to set a proper sequence of the liquibase changesets, and do not allow using the failOnError property with a true value.
You can update the files from gitHub.
But running migrations from the console could be error prone and it is not the best practice for more-developer or more-user applications so I’ll take a look at Maven in the next post. Stay tuned.