News: v0.9.3 has been released!
A while back, I wrote to introduce the first incarnation of the Carbon Five Database Migration tools, a simple though powerful framework for applying discrete changes to a database and tracking which changes have been applied to a specific database. It was inspired by Rails’ Migration support.
We’ve made a number of changes in the v0.9.1 release. We adopted some of the improvements found in Rails 2.1 as well as feedback from our users. Here’s an overview of what’s changed:
- New create, drop, and reset goals for maven plugin. Now you can create a new database, drop an existing one, or reset an existing database by dropping it, creating a new one and then migrating it. This is tested with MySQL and PostgreSQL.
- Each applied migration is tracked in the database schema_version table (instead of just the last one). Also, when it was run and how long it took to run are now saved for each.
- Validate goal now lists which migrations are pending in addition to whether the database is up to date.
- Maven artifact ids have changed (migration -> db-migration, maven-migration-plugin -> maven-db-migration-plugin) and there’s been some restructuring in the core framework.
- Maven plugin is configured a bit differently now; environments have been removed completely since maven supports a better solution out of the box: profiles.
- Maven plugin now looks for migrations in src/main/db/migrations by default; alternate locations can be specified via the <migrationsPath/> element.
- We now recommend using timestamps for migration versions instead of the NNN format, though any numerical character sequence will work.
- Reworked the algorithm for determining which migrations to run to allow for a little more flexibility. Pending migrations aren’t determined by a single version number, they’re determined by comparing what is available to what has already been run. In conjunction with timestamp versions, developers won’t be stepping on each other’s migrations.
- New and updated google code project and documentation.
As you can imagine, some of these changes aren’t backwards compatible. While we’re in pre-release (< v1.0) mode, we feel like it's more important to make the fundamental changes to build a solid foundation than to retain complete backwards compatibility. The release notes give some guidelines for upgrading.
Here’s a quick getting started guide for the maven-db-migration-plugin:
Step 1: Configure maven in your project’s pom.xml
21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 | ... <build> ... <plugin> <groupId>com.carbonfive</groupId> <artifactId>maven-db-migration-plugin</artifactId> <version>RELEASE</version> <configuration> <url>jdbc:mysql://localhost/myapp_test</url> <username>dev</username> <password>dev</password> </configuration> <dependencies> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.6</version> </dependency> </dependencies> </plugin> </build> ... <pluginRepositories> <pluginRepository> <id>c5-public-repository</id> <url>http://mvn.carbonfive.com/public</url> </pluginRepository> </pluginRepositories> ... |
Lines 29-31 configure the database connection (see the reference for more options).
Lines 35-39 specify the required dependency on our database driver.
Lines 43-48 adds the Carbon Five maven plugin repository.
Step 2: Create a migration script
In src/main/db/migrations, create a script using the format YYYYMMDDHHMMSS.sql (e.g. 20080830174515.sql). Example:
CREATE TABLE users ( id INT PRIMARY KEY, email VARCHAR(255) NOT NULL, password VARCHAR(255), enabled BOOLEAN DEFAULT 'TRUE' );
Step 3: Create the database
$ mvn db-migration:create
The supplied credentials must have the appropriate privileges, of course. If you’re not using MySQL or PostgreSQL, then do this step manually.
Step 4: Check the status of the database
$ mvn db-migration:validate
Your migration will be listed as pending and the database as not up-to-date.
Step 5: Migrate to the latest version
$ mvn db-migration:migrate
The pending migration will be applied to the database and logged in the schema_version table.
Want to learn more?
Check out the google code project page, the release notes and the sample applications.
In the near future, I’m going to look at supporting MS SQL Server and improving the SQL Script Runner. Thanks for all of the feedback and please keep it coming!
Christian









Nice work! Thanks for setting this up as a google code project. As an MS SQL Server user this will really help as I can now submit issues and fixes when and if I run into issues with MS SQL. Thanks!
Lance,
I did some testing against MS SQL Server and found one issue which has been resolved in 0.9.2-SNAPSHOT. So, I’ve successfully run all of the functionality against SQL Server 2000. If you’re up for it, switch to that SNAPSHOT and give it a try. Let me know how it goes. -Christian
I just tested against hsql 1.8 but i am having a problem created the schema version table
Caused by: java.sql.SQLException: Unexpected token: UNIQUE in statement [create table schema_version (version varchar(32) not null u
nique]
I believe that HSQL v1.9 will rectify this problem but there is no release date as yet. Am i able to use my own definition for the schema version table
cheers
Jim, it depends. If you’re using the migration manager directly in your code, then you can plug-in in a new VersionStrategy, with a custom implementation of enabledVersioning(). If you’re using the maven plugin, then there isn’t really an easy hook to do what you need to do.
What is the correct DDL SQL for creating the version table for HSQL?
Another alternative is to switch to H2Database. It’s written by the same team as Hypersonic and is actively developed, unlike HSQL.
I’m midway through a refactor which will allow for better handling of dbms-specific features. When it’s done, it will be easier to handle these cases more gracefully than the framework allows for now.
Thanks Christian
HSQL just doesn’t support the ‘unique’ constraint in the create table construct. I am using MM directly in my code.
I will also look at H2Database
cheers
Chrstian.,
Do you have an rough idea when you will be doen with the refactor
Jim: this time, I do.
I’m wrapping up a few things today and hope to release another 0.9.3-SNAPSHOT this afternoon. If no issues surface with the SNAPSHOT, I’ll release 0.9.3 Monday or Tuesday. Keep an eye on the release notes (http://code.google.com/p/c5-db-migration/wiki/ReleaseNotes) to see what’s changed and when.
Christian,
Very timely indeed. Thank you very much.
Christian,
Just picked up 0.9.3 and i can get it to run against the hsql databse. Much appreciate for the quick turn around. Now i have a question around managing the migration across a number of different databases. For instance the sql that hibenrate spits out for hsql is different to that for mysql.
Is there a mechanism to handle this at the moment?
cheers
Jim: I’ve been meaning to add the recommended approach to the wiki, but haven’t yet had time. Here’s a quick description…
Using maven profiles, you can create a profile for each database supported. In each profile, you can set a property called “dbtype”. Then, in you db-migration configuration, you can override the migrations path like this: file:src/main/resources/db/${dbtype}/migrations/*
I’ll add a more complete example to the documentation one of these days. Good luck!
Cool. I’ll give a burl
Christian,
Works like a charm. I actually ended up extended ResourceMigrationResolver and used the hibernate dialect, which i already had to set the migrationsLocations
Hi,
This is a great looking plugin - we’ve just hooked it in to our CI process and are expecting good things.
The plugin looks fully featured with the exception of rolling back to prior versions a la the way it’s done in Rails. Was this a deliberate step to enforce process, or just a feature that has not been implemented yet?
Thanks,
- max
@Maxim: leaving rollback out was a deliberate decision. Not every migration has an easy-to-write corresponding rollback (e.g. destructive changes). And in my personal experience, I’ve never really needed to rollback a migration in development. We develop our migration against a unit test database that’s easy to reset. Once a migration is satisfactory, it’s run against a local development database, then checked into VCS for the rest of the team. If we need to undo something in a previous migration, we simply do it in a new migration. We’ve had scenarios where migration N adds a column and the migration N + 2 (or something) removes it. That works fine.
Have you found a strong case for rolling back in your experience?