I was under the impression that changesets within migration scripts were transactional, but I am seeing that in practice they are not.
For the simplest example of this, create a basic changeset entry, maybe as follows:
changeSet(author: "some_email@server.com", id: "1-1", description: "An example changeset for a changelog.groovy.") {
createTable(tableName: "table_name") {
column(autoIncrement: "true", name: "id", type: "BIGINT") {
constraints(nullable: "false", primaryKey: "true")
}
column(name: "version", type: "BIGINT") {
constraints(nullable: "false")
}
column(name: "name", type: "VARCHAR(64)") {
constraints(nullable: "false")
}
column(name: "name", type: "VARCHAR(64)") {
constraints(nullable: "false")
}
}
}
Now, obviously we cannot add two columns of the same name, so this should fail - and rollback. But it doesn't rollback. The table is created and the first column is added - despite the fact it is a "bad" changeset.
So, the questions are -
1) are changelog.groovy changesets transactions?
2) is grails dmb-update supposed to execute changesets transactionally?
3) if so, what did we configure incorrectly?
Database migrations in Grails are not transactional. If you need the ability to rollback a failed changeset you have to write the rollback yourself.
As Burt points out "The primary issue is that transactions, rollback, etc. are primarily a data/DML concept. Some databases have at least partial support for rolling back structural/DDL changes, but it's very impractical in the general case".