Java.DBMigrationTools.What is runAlways and how does it differ from runOnChange?

These are Liquibase-specific escape hatches, and interviewers expect you to know why they exist and why they’re dangerous.


runAlways

runAlways=true means the changeset executes every time Liquibase runs, even if it was already applied.

Example

<changeSet id="refresh_view" author="stanley" runAlways="true">
    <sql>
        REFRESH MATERIALIZED VIEW user_stats;
    </sql>
</changeSet>

Key properties

  • Ignores execution history
  • Runs on every startup / deploy
  • Checksum is irrelevant
  • History row still exists, but execution is repeated

Typical use cases (valid)

  • Refreshing views
  • Recreating derived data
  • Syncing reference data
  • Granting permissions

Why it’s risky

  • Can be expensive
  • Can lock tables
  • Easy to hide performance problems
  • Never use for schema changes

runOnChange

runOnChange=true means the changeset runs again only if its contents change.

Example

<changeSet id="recreate_function" author="stanley" runOnChange="true">
    <sql>
        CREATE OR REPLACE FUNCTION normalize_name(text) RETURNS text AS $$
        BEGIN
            RETURN lower(trim($1));
        END;
        $$ LANGUAGE plpgsql;
    </sql>
</changeSet>

Key properties

  • Liquibase stores checksum
  • If file content changes → checksum changes → re-run
  • If unchanged → skipped
  • Still deterministic

Typical use cases (valid)

  • Stored procedures
  • Functions
  • Triggers
  • Views (sometimes)

Why it’s risky

  • Encourages editing applied migrations
  • Can surprise reviewers (“why did this run again?”)
  • Dangerous if mixed with data changes

Side-by-side comparison

AspectrunAlwaysrunOnChange
Runs every time✅ Yes❌ No
Runs on file change❌ No✅ Yes
Uses checksum❌ Ignored✅ Required
Deterministic❌ No⚠️ Semi
Safe for schema❌ No❌ No
Typical targetDerived dataCode-like DB objects

What NOT to do (red flags 🚨)

❌ Use either for:

  • ALTER TABLE
  • DROP COLUMN
  • irreversible data changes

❌ Use to “fix” a bad migration instead of adding a new one

Interview-ready explanation (2 sentences)

runAlways forces a changeset to execute on every Liquibase run regardless of history, while runOnChange re-executes a changeset only when its contents change and the checksum differs. Both are intended for derived or code-like database objects, not for schema evolution, and should be avoided for production schema changes.


Senior rule of thumb (remember this)

If it changes schema or business data, it should run once and never again.

This entry was posted in Без рубрики. Bookmark the permalink.