Database migration tools, such as Liquibase, are capable of upgrading the database to a specific version, using change sets. Liquibase provides a clean API and command line client allowing users to perform migrations.
In many situations the command line client is sufficient. Whenever a new change set gets added, the developer executes that migration on its local RDBMS. However, sometimes it might be desirable to upgrade your database to the latest version automatically. In this blog post I will explain how to automate Liquibase migrations.
The migration should be performed at application startup, before any ORM technologies are activated, because our mappings expect the latest database version. By migrating the database first, we could even use the Hibernate Schema Validator to verify our database schema after all migration scripts have been executed.
We decided to put our (Liquibase) migration logic inside a data source “decorator”, which performs the migration post construct. Because Hibernate requires our data source as a property, we ensure the migration is done first. Also, the data source has access to our JDBC connection, which we need for the migration.
Configuration of our data source decorator bean goes as follows:
<bean id="dataSource" class="org.jarbframework.migrations.MigratingDataSource">
<property name="driverClassName" value="org.hsqldb.jdbcDriver"/>
<property name="url" value="jdbc:hsqldb:mem:jarb"/>
<property name="username" value="sa"/>
<property name="password" value=""/>
Our decorator, here known as MigratingDataSource, wraps the regular data source, and executes the migration upon startup using @PostConstruct. Spring recognizes this annotation, and executes the method automatically after bean initialization. Now, whenever our application gets started the database migration will be performed.
Every component described above is made available in JaRB (Java Repository Bridge).
Bonus: Data feeding
Hibernate allows the database to be generated using hbm2ddl.auto=create. Liquibase can replace this functionality, providing more flexible schema generation. However, Hibernate also looks in the classpath for an import.sql file, executing each SQL statement inside it. Whenever the switch is made to Liquibase, this import script is no longer executed automatically. Fortunately JaRB provides a component with similar functionality.
To execute the ‘import.sql’ on startup, simply define the following bean:
<property name="sqlResource" value="classpath:import.sql"/>
<property name="dataSource" ref="dataSource"/>
Data feeding logic will automatically be executed after bean initialization. Because the populator uses our migrating data source, we configure our migration to be done first.
We are also experimenting with an Excel based database populator, but that will be described in a future blog post.