Dropwizard Migrations
The dropwizard-migrations
module provides you with a wrapper for Liquibase database
refactoring.
Configuration
Like Dropwizard JDBI3, your configuration class needs a
DataSourceFactory
instance:
public class ExampleConfiguration extends Configuration {
@Valid
@NotNull
private DataSourceFactory database = new DataSourceFactory();
@JsonProperty("database")
public DataSourceFactory getDataSourceFactory() {
return database;
}
}
Adding The Bundle
Then, in your application’s initialize
method, add a new MigrationsBundle
subclass:
@Override
public void initialize(Bootstrap<ExampleConfiguration> bootstrap) {
bootstrap.addBundle(new MigrationsBundle<ExampleConfiguration>() {
@Override
public DataSourceFactory getDataSourceFactory(ExampleConfiguration configuration) {
return configuration.getDataSourceFactory();
}
});
}
If you are using Dropwizard Hibernate or Dropwizard JDBI3 in your application,
you can use these techniques within a CustomChange
to make bigger data migrations.
Therefore you need to provide an instance of these to the MigrationsBundle
like in the following example:
@Override
public void initialize(Bootstrap<ExampleConfiguration> bootstrap) {
bootstrap.addBundle(new MigrationsBundle<ExampleConfiguration>() {
@Override
public DataSourceFactory getDataSourceFactory(ExampleConfiguration configuration) {
return configuration.getDataSourceFactory();
}
@Override
public Map<String, Object> getScopedObjects() {
Map<String, Object> scopedObjects = new HashMap<>();
scopedObjects.put("hibernateSessionFactory", hibernateBundle.getSessionFactory());
return scopedObjects;
}
});
}
In your CustomChange
you can retrieve the registered SessionFactory
with this code:
public void execute(Database database) throws CustomChangeException {
Scope.getCurrentScope().get("hibernateSessionFactory", SessionFactory.class);
}
Defining Migrations
Your database migrations are stored in your Dropwizard project, in
src/main/resources/migrations.xml
. This file will be packaged with your application, allowing you to
run migrations using your application’s command-line interface. You can change the name of the migrations
file used by overriding the getMigrationsFileName()
method in MigrationsBundle
.
For example, to create a new people
table, you might create an initial migrations.xml
like
this:
<?xml version="1.0" encoding="UTF-8"?>
<databaseChangeLog
xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog
http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.1.xsd">
<changeSet id="1" author="codahale">
<createTable tableName="people">
<column name="id" type="bigint" autoIncrement="true">
<constraints primaryKey="true" nullable="false"/>
</column>
<column name="fullName" type="varchar(255)">
<constraints nullable="false"/>
</column>
<column name="jobTitle" type="varchar(255)"/>
</createTable>
</changeSet>
</databaseChangeLog>
For more information on available database refactorings, check the Liquibase documentation.
Checking Your Database’s State
To check the state of your database, use the db status
command:
java -jar hello-world.jar db status helloworld.yml
Dumping Your Schema
If your database already has an existing schema and you’d like to pre-seed your migrations.xml
document, you can run the db dump
command:
java -jar hello-world.jar db dump helloworld.yml
This will output a Liquibase change log with a changeset capable of recreating your database.
Tagging Your Schema
To tag your schema at a particular point in time (e.g., to make rolling back easier), use the
db tag
command:
java -jar hello-world.jar db tag helloworld.yml 2012-10-08-pre-user-move
Migrating Your Schema
To apply pending changesets to your database schema, run the db migrate
command:
java -jar hello-world.jar db migrate helloworld.yml
Warning
This will potentially make irreversible changes to your database. Always check the pending DDL
scripts by using the --dry-run
flag first. This will output the SQL to be run to stdout.
Note
To apply only a specific number of pending changesets, use the --count
flag.
Rolling Back Your Schema
To roll back changesets which have already been applied, run the db rollback
command. You will
need to specify either a tag, a date, or a number of changesets to roll back to:
java -jar hello-world.jar db rollback helloworld.yml --tag 2012-10-08-pre-user-move
Warning
This will potentially make irreversible changes to your database. Always check the pending DDL
scripts by using the --dry-run
flag first. This will output the SQL to be run to stdout.
Testing Migrations
To verify that a set of pending changesets can be fully rolled back, use the db test
command,
which will migrate forward, roll back to the original state, then migrate forward again:
java -jar hello-world.jar db test helloworld.yml
Warning
Do not run this in production, for obvious reasons.
Preparing A Rollback Script
To prepare a rollback script for pending changesets before they have been applied, use the
db prepare-rollback
command:
java -jar hello-world.jar db prepare-rollback helloworld.yml
This will output a DDL script to stdout capable of rolling back all unapplied changesets.
Generating Documentation
To generate HTML documentation on the current status of the database, use the db generate-docs
command:
java -jar hello-world.jar db generate-docs helloworld.yml ~/db-docs/
Dropping All Objects
To drop all objects in the database, use the db drop-all
command:
java -jar hello-world.jar db drop-all --confirm-delete-everything helloworld.yml
Warning
You need to specify the --confirm-delete-everything
flag because this command deletes
everything in the database. Be sure you want to do that first.
Fast-Forwarding Through A Changeset
To mark a pending changeset as applied (e.g., after having backfilled your migrations.xml
with
db dump
), use the db fast-forward
command:
java -jar hello-world.jar db fast-forward helloworld.yml
This will mark the next pending changeset as applied. You can also use the --all
flag to mark
all pending changesets as applied.
Support For Adding Multiple Migration Bundles
Assuming migrations need to be done for two different databases, you would need to have two different data source factories:
public class ExampleConfiguration extends Configuration {
@Valid
@NotNull
private DataSourceFactory database1 = new DataSourceFactory();
@Valid
@NotNull
private DataSourceFactory database2 = new DataSourceFactory();
@JsonProperty("database1")
public DataSourceFactory getDb1DataSourceFactory() {
return database1;
}
@JsonProperty("database2")
public DataSourceFactory getDb2DataSourceFactory() {
return database2;
}
}
Now multiple migration bundles can be added with unique names like so:
@Override
public void initialize(Bootstrap<ExampleConfiguration> bootstrap) {
bootstrap.addBundle(new MigrationsBundle<ExampleConfiguration>() {
@Override
public DataSourceFactory getDataSourceFactory(ExampleConfiguration configuration) {
return configuration.getDb1DataSourceFactory();
}
@Override
public String name() {
return "db1";
}
});
bootstrap.addBundle(new MigrationsBundle<ExampleConfiguration>() {
@Override
public DataSourceFactory getDataSourceFactory(ExampleConfiguration configuration) {
return configuration.getDb2DataSourceFactory();
}
@Override
public String name() {
return "db2";
}
});
}
To migrate your schema:
java -jar hello-world.jar db1 migrate helloworld.yml
and
java -jar hello-world.jar db2 migrate helloworld.yml
Note
Whenever a name is added to a migration bundle, it becomes the command that needs to be run at the command line.
eg: To check the state of your database, use the status
command:
java -jar hello-world.jar db1 status helloworld.yml
or
java -jar hello-world.jar db2 status helloworld.yml
By default the migration bundle uses the “db” command. By overriding you can customize it to provide any name you want and have multiple migration bundles. Wherever the “db” command was being used, this custom name can be used.
There will also be a need to provide different change log migration files as well. This can be done as
java -jar hello-world.jar db1 migrate helloworld.yml --migrations <path_to_db1_migrations.xml>
java -jar hello-world.jar db2 migrate helloworld.yml --migrations <path_to_db2_migrations.xml>
More Information
If you are using databases supporting multiple schemas like PostgreSQL, Oracle, or H2, you can use the
optional --catalog
and --schema
arguments to specify the database catalog and schema used for the
Liquibase commands.
For more information on available commands, either use the db --help
command, or for more
detailed help on a specific command, use db <cmd> --help
.