Companion code for the Flyway vs Liquibase article: checksum validation, out-of-order and repeatable migrations, baselining an existing schema, Flyway Community's undo/diff/deploy stubs, concurrent-startup locking for both tools, Liquibase changeset identity and rollback (auto-generated vs explicit), a verified Liquibase 5.0.3 filename-caching defect, the new OSS license service, the FSL license change, and running both tools against one database. Co-Authored-By: Claude Sonnet 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Q6XdRjtsp4862EM44T7i9a
59 lines
4.1 KiB
Markdown
59 lines
4.1 KiB
Markdown
# 9. Liquibase: anatomy of an update
|
|
|
|
[← 8. Concurrent startup and locking](08-concurrent-startup-and-locking.md) · [Index](../README.md) · Next: [10. Rollback: auto-generated vs explicit →](10-rollback-auto-generated-vs-explicit.md)
|
|
|
|
Liquibase's unit of change is a **changeset** inside a **changelog** — one YAML (or XML, or JSON,
|
|
or SQL) document listing every change in order, rather than one file per change. This module's
|
|
main changelog is
|
|
[`db.changelog-master.yaml`](../src/main/resources/db/changelog/db.changelog-master.yaml);
|
|
[`LiquibaseHappyPathTest`](../src/test/java/com/ankurm/dbmigrations/liquibase/LiquibaseHappyPathTest.java)
|
|
uses a small inline one — a `createTable` changeset, then an `insert` changeset — run through the
|
|
classic [`Liquibase`](../src/test/java/com/ankurm/dbmigrations/liquibase/LiquibaseTestSupport.java)
|
|
facade directly, with no Spring involved, so the mechanics are visible without an application
|
|
context in the way.
|
|
|
|
```
|
|
databasechangelog:
|
|
ID | AUTHOR | FILENAME | ORDEREXECUTED | EXECTYPE
|
|
-----------------+--------+-------------+---------------+---------
|
|
1-create-account | ankurm | master.yaml | 1 | EXECUTED
|
|
2-seed-account | ankurm | master.yaml | 2 | EXECUTED
|
|
|
|
account table:
|
|
ID | OWNER
|
|
---+------------------
|
|
1 | Katherine Johnson
|
|
```
|
|
|
|
(from [`docs/output/09-liquibase-happy-path.txt`](output/09-liquibase-happy-path.txt))
|
|
|
|
`DATABASECHANGELOG` is Liquibase's equivalent of `flyway_schema_history`, but the identity of a
|
|
changeset is different in kind from Flyway's version numbers: it's the triple of `id`, `author`,
|
|
and the changelog `filename` it was declared in. Two changesets with the same `id` in two
|
|
*different* files are different changesets to Liquibase; the same `id` twice in the *same* file
|
|
is a configuration error. There is no numeric ordering at all — order comes purely from position
|
|
in the changelog, top to bottom.
|
|
|
|
<svg viewBox="0 0 700 190" xmlns="http://www.w3.org/2000/svg" font-family="monospace" font-size="13">
|
|
<rect x="20" y="20" width="280" height="140" rx="6" fill="#eef2ff" stroke="#4f46e5"/>
|
|
<text x="160" y="42" text-anchor="middle">master.yaml</text>
|
|
<rect x="35" y="55" width="250" height="35" fill="#fff" stroke="#94a3b8"/>
|
|
<text x="160" y="77" text-anchor="middle" font-size="11">changeSet id: 1-create-account</text>
|
|
<rect x="35" y="100" width="250" height="35" fill="#fff" stroke="#94a3b8"/>
|
|
<text x="160" y="122" text-anchor="middle" font-size="11">changeSet id: 2-seed-account</text>
|
|
<path d="M300 90 L360 90" stroke="#334155" stroke-width="2" marker-end="url(#a5)"/>
|
|
<rect x="360" y="40" width="300" height="120" rx="6" fill="#fdf2f8" stroke="#be185d"/>
|
|
<text x="510" y="62" text-anchor="middle">DATABASECHANGELOG</text>
|
|
<text x="380" y="88" font-size="11">id=1-create-account, author=ankurm,</text>
|
|
<text x="380" y="103" font-size="11">filename=master.yaml → EXECUTED</text>
|
|
<text x="380" y="128" font-size="11">id=2-seed-account, author=ankurm,</text>
|
|
<text x="380" y="143" font-size="11">filename=master.yaml → EXECUTED</text>
|
|
<defs><marker id="a5" markerWidth="8" markerHeight="8" refX="6" refY="4" orient="auto"><path d="M0,0 L8,4 L0,8 z" fill="#334155"/></marker></defs>
|
|
</svg>
|
|
|
|
## Going deeper
|
|
|
|
- **`update()` and the newer command-framework path.** Liquibase 5's classic `Liquibase.update(...)` facade internally delegates to a `CommandScope`/`UpdateCommandStep` implementation rather than the older direct-execution path — visible in every stack trace in this module (chapter [11](11-liquibase-locking.md) has a full one). It doesn't change behaviour for straightforward changesets, but it's worth knowing when a stack trace looks unfamiliar next to older Liquibase tutorials.
|
|
- [Liquibase changelog structure](https://docs.liquibase.com/concepts/changelogs/home.html) (`rel="nofollow"`) — the full list of supported changelog formats and the changeset identity rules referenced above.
|
|
- Liquibase also supports **preconditions** and **contexts/labels** for conditionally running changesets — out of scope for this module, but the natural next thing to read once changesets and changelogs make sense.
|