Several documentation.red-gate.com and liquibase.com URLs added in the previous commit had since moved (Redgate restructured its docs under /flyway/reference/, Liquibase Pro pricing moved to /pricing); this repoints them at the current, verified-200 pages. Also captures docs/output/16-liquibase-lock-defaults-javap.txt, the trimmed javap output backing chapter 11's claim about Liquibase's default lock-poll and lock-wait settings, which chapter 11 previously asserted without a committed artifact to back it. Co-Authored-By: Claude Sonnet 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Q6XdRjtsp4862EM44T7i9a
4.5 KiB
10. Rollback: auto-generated vs explicit
← 9. Liquibase: anatomy of an update · Index · Next: 11. Liquibase locking →
Chapter 7 showed Flyway Community has no working undo at all.
Liquibase's answer is rollback() — and whether it works depends entirely on the change type.
When Liquibase can invert a change on its own
createTable is one of the change types Liquibase knows how to invert without being told how —
it just runs DROP TABLE.
LiquibaseRollbackAutoTest
writes no rollback: block anywhere in its changelog, calls update(), confirms the session
table exists, then calls rollback(1, ...):
after update(): session table exists = true
after rollback(1): session table exists = false
(from docs/output/10-liquibase-rollback-auto.txt)
When it can't
insert is not in that list.
LiquibaseRollbackFailTest
applies a createTable changeset followed by an insert changeset, then calls rollback(1, ...)
— which only asks to roll back the most recent changeset, the insert. It fails for real:
after update(): both changesets applied
rollback(1) threw: liquibase.exception.CommandExecutionException
message: liquibase.exception.LiquibaseException: liquibase.exception.RollbackFailedException: liquibase.exception.RollbackImpossibleException: No inverse to liquibase.change.core.InsertDataChange created
(from docs/output/11-liquibase-rollback-no-inverse.txt)
The fix: write the inverse yourself
LiquibaseRollbackExplicitTest
is the same insert changeset, this time carrying its own rollback: block:
- insert:
tableName: audit_log
columns:
- {column: {name: event, value: 'system-start'}}
rollback:
- delete:
tableName: audit_log
where: event='system-start'
rollback(1, ...) now succeeds — the table stays, the row is gone:
audit_log after rollback(1) — table still exists, the row is gone:
ID | EVENT
---+------
(0 rows)
(from docs/output/12-liquibase-rollback-explicit.txt)
Going deeper
- Which change types Liquibase can auto-generate a rollback for (
rel="nofollow") —createTable,addColumn, and a handful of other structural changes; almost anything involving data (insert,update,delete, mostsql:changes) needs an explicitrollback:block. - A team relying on rollback in production is really relying on discipline: every changeset that touches data needs its rollback written and tested at the time the changeset is written, not discovered missing during an actual incident —
rollback(1, ...)failing is the worst possible moment to learninserthas no inverse. - Liquibase also supports
rollbackCount,rollbackToDateand rolling back by tag — this module exercises only the single-changesetrollback(int, ...)overload.