Database schema migration with LiquiBase

January 8, 2008

One item of concern for me during development is figuring out what to do one I have actual live data on a database, and I can’t do schema updates by dropping all tables and letting hibernate re-create them.

A solution I’ve run into today that seems promising is LiquiBase. It’s still very much in development but they are working on roughly what I want.

The idea behind liquibase is fairly simple – store a list of database changes to a file, and let the user run them. I think it has a way to keep track of which changes were already run in the past, and then it can roll forward any new changesets you add to the file. This is a great idea!

The only trouble I have with it is that I’m using hibernate to generate my database schemas and I’m generally pretending I don’t know anything about the schemas it generates (sequences, foreign keys, foreign key names, not null constraints etc.). LiquiBase generally assumes you know what changes are being made and you’ll be entering them into the changesets file as you go.

LiquiBase does provide a diff tool which allows me to generate XML changesets that would convert one schema to another. I should be able to take that XML diff and “fix it up” to replace drop/create with a rename, or provide a custom data upgrader.

The last bit is one thing that seems promising. I can specify a Java class which is instantiated and used to roll forward or back a changeset. I think this will be something I’d use to manage the “real” schema changes – adding new relationships. Without something like this, there’s no way for me to transform the data properly. So, I can tweak the changesets to prepare my data upgrade, then have it invoke my class, then finish the job. Probably it’ll create new columns and remove constraints first, then run my custom code, then drop columns and add constraints afterwards.

So, a tool with promise. I haven’t managed to use it yet, unfortunately. I’m putting all my tables into a seperate postgres schema and the schema support is temporarily incomplete, which means I’d have to do a bunch of messing around to get it to work easily for me. Once I get closer to the point of really needing it, hopefully that’ll be fixed or I can copy the tables into the public schema temporarily for diffing purposes in order to figure out what hibernate changed.

Ideally there would be a tool I could use to take an existing changeset file and persistence unit (persistence.xml and a bunch of annotated classes) and generate the changes I could put into the LiquiBase changeset file (after fixing up anything not automatically handled by the diffing tool). That way, just before I make a “release” to production, I would run that tool and it would do its magic.

I can think of a way to do that manually now – I could create a temporary database using the old XML, and another temporary database with the hibernate classes, and diff them. Currently my ejb3unit test cases leave behind the latest hibernate-generated database, so I just need a copy of the last released database to do my diff. Then, I drop that into my XML file and my next deploy should upgrade the database automatically. I’d also have to turn off the hibernate’s schema update and only use this scheme to manage the database being used in Java EE, both in development and production, but that’s a good thing since it’ll mean I’m testing the schema changesets during development.

Still, this schema issue is a bit of a pain to work around, so I’ll wait a bit and see if I can get a fix for that before I spend any more time on this.


Hibernate + fetch=FetchType.LAZY making trouble

January 6, 2008

Now, for the third time, I’ve run into some weird and wonderful situation where a lazy object wasn’t initialized when I was using it.  When will I learn?  Don’t use FetchType.LAZY unless you’re really know what you’re doing, and test carefully afterwards.  The precise problem I seem to be having is that my hashCode() and equals() methods don’t work.  Anyway, a word of caution!