In modern software developing, versioning your source code is a most do and you can easilly find robust opensource and privative solutions to mantain a healthy versioned code. In the other hand, most developers agreed that versioning the changes made in your data model is as important than versioning your source code, but the tools available to do this task are not as extended and documented as the first ones.
In most projects that I have had the opportunity to participate the usual way to version the database is creating SQL scripts and run them in a progresive way. This does the job but have some drawbacks, for example:
1 If you use an ORM for the persistence of your project then you must write the versioning scripts for all the different database providers that you want to support.
2 If you need rollback functionallity then you must mantain two scripts.
3 If you have different branches in your projects merging changes can be a tiring process.
4. You must write plumbing code for versioning in your project. The old reinventing the wheel problem.
We decided to try Liquibase, an interesting database versioning tool that solves most the problems presented, mantaining the changes of your database in an "engine independent" way and supports rollbacks, diffs and tagging. We are not explaining how to use this tool here because the official documentation that you can find in liquibase.com is really good, what we will be explaining here is something that we couldn't find in the official documentation and this is including the liquibase library directly in you java code and use this as an API.
Liquibase was intended to be used via command line, ANT scripts and maven. In our case this wasn't enough and we wanted to be able the call and use the liquibase services directly in our java code to have the flexibility to do runtime updates in our own project. We tried to access directly the Liquibase object with no luck, we experimented many exceptions and hard times because the source code of liquibase is not documented as we would like, so the final desition was using the command line integration class.
First you need to download liquibase 2.0 and the jdbc connector for your database and include them in your project libraries. Next you need to extend from the class liquibase.integration.commandLine.Main (yes this is really ugly, we will still searching a better way).
public class DatabaseVersioningService extends liquibase.integration.commandline.Main implements DatabaseVersioningServiceLocal {
private static final String DATABASENAME_CHANGELOG_PARAM = "DATABASENAME";
private static final String CHANGELOG_PATH = "changeLogs/changelog_master.xml";
private static final String MYSQL_CLASS_DRIVER = "com.mysql.jdbc.Driver";
private static final String UPDATE_COMMAND = "update";
public void updateToHEAD(String dbUser, String dbPassword) {
try {
setMigrationParameters(dbUser, dbPassword);
applyDefaults();
configureClassLoader();
doMigration();
} catch (Throwable ex) {
ex.printStackTrace();
}
}
private void setMigrationParameters(String dbUser, String dbPassword, String command) throws URISyntaxException, SQLException {
changeLogFile = getClass().getResource(CHANGELOG_PATH).getPath();
username = dbUser;
password = dbPassword;
driver = MYSQL_CLASS_DRIVER;
url = new URI(padposDataSource.getConnection().getMetaData().getURL());
command = command;
}
}
Like you can see in the sample code is really simple but figure out this from the liquibase source code wasn't that easy, so we hope this can help someone else that wants to integrate liquibase directly in code. We will be studying liquibase code and maybe we will be writting a service tier to make this in a cleaner and elgant way.