Files
spring-boot-demo/db-migrations-flyway-liquibase/docs/06-baselining-an-existing-database.md
T
asmhatreandClaude Sonnet 5 67e1b2d8a9 db-migrations-flyway-liquibase: fix dead Redgate/Liquibase doc links and back the lock-defaults claim with a real transcript
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
2026-09-15 07:31:49 +00:00

57 lines
3.7 KiB
Markdown

# 6. Baselining an existing database
[← 5. Repeatable migrations](05-repeatable-migrations.md) · [Index](../README.md) · Next: [7. Why there is no undo →](07-why-there-is-no-undo.md)
Every migration tool eventually meets a database it didn't create. Someone hand-ran DDL for five
years, and now the team wants Flyway to take over from here — without dropping the schema and
replaying history that never actually happened through Flyway.
[`FlywayBaselineTest`](../src/test/java/com/ankurm/dbmigrations/flyway/FlywayBaselineTest.java)
sets this up literally: a `legacy_account` table is created with plain JDBC, with one row already
in it, *before Flyway is ever involved*. Pointing an unconfigured Flyway at that database refuses
outright — this is the same safety check from chapter [1](01-the-problem-and-mental-model.md), and
it's what makes baselining necessary rather than optional:
```
FlywayException: Found non-empty schema(s) "PUBLIC" but no schema history table. Use baseline() or set baselineOnMigrate to true to initialize the schema history table.
```
Turning on `spring.flyway.baseline-on-migrate=true` (with `baseline-version=1` and a
`baseline-description`) fixes it. `V1__init.sql` — written to describe the schema that *already
exists* — never actually runs; instead Flyway inserts a `BASELINE`-typed row claiming version 1 is
already accounted for, and only `V2__add_status_column.sql` executes for real:
```
installed_rank | version | description | type | success
---------------+---------+-------------------------------------------+----------+--------
-1 | NULL | << Flyway Schema History table created >> | TABLE | true
1 | 1 | pre-flyway schema | BASELINE | true
2 | 2 | add status column | SQL | true
```
(from [`docs/output/05-flyway-baseline.txt`](output/05-flyway-baseline.txt))
The pre-existing row survives untouched, and gains the new column:
```
ID | OWNER | STATUS
---+-----------------+-------
1 | pre-flyway-data | ACTIVE
```
<blockquote style="border-left:4px solid #ca8a04;background:#fefce8;padding:12px 16px;margin:16px 0;">
<strong>Trap:</strong> the baseline row's <code>description</code> is not a fixed string. It is
exactly whatever <code>spring.flyway.baseline-description</code> was set to — in this test,
literally <code>"pre-flyway schema"</code>. A different, fixed marker — <code>&lt;&lt; Flyway
Schema History table created &gt;&gt;</code> — belongs to a <em>different</em> row (rank
<code>-1</code>, type <code>TABLE</code>), created the moment the history table itself is created,
whether or not baselining ever happens. Confusing the two is an easy way to write a broken
assertion or a broken monitoring query — this module's own first draft did exactly that.
</blockquote>
## Going deeper
- **`baselineVersion` decides what "already accounted for" means**, and it matters which value you pick — chapter [14](14-running-both-at-once.md) shows the same mechanism used with `baseline-version=0` instead of `1`, for a database whose existing schema *doesn't* match any of your migration files at all.
- [Flyway `baseline` command reference](https://documentation.red-gate.com/flyway/reference/commands/baseline) (`rel="nofollow"`) — the one-time `flyway baseline` CLI/API call this test's `baselineOnMigrate=true` triggers automatically on first startup.
- Baselining is a one-way door in the sense that matters: once version 1 is marked as baselined, Flyway will never again check whether the schema it describes actually matches `V1__init.sql`'s content — that specific file's checksum is simply never looked at again for this database.