Database / Liquibase interview questions
How does Liquibase handle transactions during migration?
By default, Liquibase wraps each changeSet in a database transaction. If any change within a changeSet fails, the entire changeSet is rolled back and Liquibase stops. This transactional wrapper ensures that a changeSet either succeeds completely or leaves the database unchanged — partial application of a changeSet is prevented.
However, not all SQL statements can run inside a transaction in all databases. For example, CREATE INDEX CONCURRENTLY in PostgreSQL, DDL statements in Oracle (which auto-commit), and some MySQL table operations are not transactional. For these cases, Liquibase provides the runInTransaction attribute on a changeSet:
<changeSet id="create-index-concurrently" author="henry" runInTransaction="false"> <sql>CREATE INDEX CONCURRENTLY idx_order_created ON "order"(created_at)</sql> <rollback> <sql>DROP INDEX IF EXISTS idx_order_created</sql> </rollback> </changeSet>
Setting runInTransaction="false" means that if the changeSet fails mid-execution, the already-executed statements within it are not automatically rolled back — you may be left with a partially applied changeSet. This is an acceptable trade-off for operations that genuinely cannot run in a transaction (like concurrent index creation, which cannot hold a table lock for the duration of a transaction in PostgreSQL).
A changeSet with runInTransaction="false" should contain the minimum number of operations necessary, and the rollback block becomes critical since Liquibase will not automatically undo partial work if the changeSet fails.
More Related questions...