Today I spend most of my time migrating a database. Luckily the version-controlled with Liquibase. Liquibase prmotes on its website as:
Track, version, and deploy database changes
The single changes to apply can be described in different ways and grouped into so-called changesets. Changesets are the unit that liquibase tracks, so a once applied changeset is not run again. For further information dig into the documentation.
So updating should be nothing special, right? Well, there are some hurdles.
Know your Workflow
Working with liquibase is straightforward, but nothing prevents you from locking yourself. The must-know commands of liquibase are:
update
or for those using the maven pluginliquibase:update
. This command executes all changesets which are not yet marked as executed.sync
or mavenliquibase:sync
. Marks all local changesets as executed in the database.status
or mavenliquibase:status
. Prints out which changesets are not yet marked as executed.
The basic workflow looks like this. You start developing your changes, check what to apply with status
. Execute the updates with update
and then mark the changes as executed with sync
.
Lessons Learned 1: Never run sync without being sure that every local changeset applied successfully! If you are in doubt, run update
again ;-).
Oh shit, I synced, not executed changes!
Yes, well, I did. Googled aaaaaannnd - Nothing besides “Don’t do this”. Well, no shit Sherlock! But don’t worry, I have your back ;-)
First of all, we need to identify changes that didn’t execute yet. If we have the list of not executed changesets, we can check the Databasechangelog table. This table contains all changesets which are executed and is the source on which the update command relies. For details find the documentation here.
In this situation, the column FILENAME
, AUTHOR
and ID
are important. The filename corresponds to the changelog file. In the changeset definition within the changelog, we can find the author and id.
delete from databasechangelog where filename=:changelogFileName and author=:authorOfChangeset and id=:changeSetID
Now you can execute the changelogs with update
and, if succeeded, run sync
. Your changes should be applied now. Lessons learned 2: You can recover from ignoring lessons learned 1, but it is risky!
I was too hectically. I’ve cleaned the log..
Well, shit. But were there, done that and recovered!
We proceed like in the last section. But first, let’s refill the database changelog table. It is straightforward by executing sync
. Remember it marks all locally present changes as executed. From here, we need to delete the rows with the not yet executed changes and apply them with update
.
Lessons learned 3: You can recover from total screw-up-situation, but try to avoid them!
Summary
It was an exciting and challenging day. Liquibase is a very powerful tool and a must-have in every developer’s toolkit. Learning always involves failing, but sadly the internet lacks recovery guides for liquibase. I hope my three lessons learned can help you not do my faults or recover from them.