Mysql

80 posts in this section

Diff, Snapshot, and Reverse Engineering: Onboarding Existing Databases

Most Liquibase tutorials start with a blank database. Most real projects start with a production database that has been evolving for years without version control. This article covers the complete workflow for adopting Liquibase on an existing database — generating a baseline changelog, bootstrapping Liquibase tracking, detecting drift between environments, and maintaining snapshots for offline comparisons. The Onboarding Problem An existing database has no DATABASECHANGELOG table. Running liquibase update with a fresh changelog would try to create tables that already exist, causing immediate failures.

Continue reading »

Introduction to Spring Batch: What, Why, and Architecture

Every application has a class of work that doesn’t fit the request-response model: process 2 million orders overnight, generate 500,000 monthly statements, migrate 10 years of legacy data before Monday morning. This work needs to be reliable, restartable after failures, and fast enough to finish in the available window. That’s what Spring Batch is built for. This article covers what Spring Batch is, when to use it, and how its architecture works.

Continue reading »

Introduction: Why Database Versioning Matters

Your application code is in Git. Every change is tracked, reviewed, and reversible. Your database schema is not — it lives in someone’s head, a shared wiki page, or a folder of SQL scripts with names like fix_final_v3.sql. This is the problem Liquibase solves. The Problem: Database Drift On a typical team without database versioning: Developer A adds a column locally and forgets to tell anyone Developer B’s tests fail on a table that exists on A’s machine but not on B’s Staging has 3 extra columns that production doesn’t — or vice versa Nobody knows what the “correct” schema state is Deploying to production means manually running SQL scripts while hoping nothing was missed This is database drift — the schema diverges between environments and nobody tracks when or why.

Continue reading »

JobParameters, ExecutionContext, and Job Restartability

Introduction Two mechanisms let you pass information into and through a Spring Batch job: JobParameters — input values provided at launch time (a date, a file path, a run ID). They are immutable and persisted to BATCH_JOB_EXECUTION_PARAMS. ExecutionContext — a key-value map that steps can read and write during execution. It is persisted after each chunk commit, enabling restartability. Understanding both is essential for building jobs that can be safely re-run, restarted after failure, and parameterised for different data sets.

Continue reading »

JobRepository and Batch Metadata: How Spring Batch Tracks Everything

Introduction Every time Spring Batch runs a job it records the run’s history in a set of relational tables. This metadata is not optional — it is what makes Spring Batch reliable. Without it there would be no restart capability, no duplicate-run prevention, and no audit trail. Understanding the metadata layer is essential for debugging failures, building monitoring dashboards, and designing restartable jobs. In this article you will learn: The role of JobRepository and JobExplorer in the Spring Batch architecture The six metadata tables — their schema, purpose, and relationships How Spring Batch uses these tables to enable restartability How to query batch history directly in MySQL How to access metadata programmatically with JobExplorer Key changes in Spring Batch 5 (removed MapJobRepositoryFactoryBean, new testing approach) All examples use Spring Boot 3.

Continue reading »

Kubernetes Deployments: Jobs, Init Containers, and Helm Hooks

Spring Boot’s Liquibase auto-run works fine for a single instance. In Kubernetes, where multiple pods start simultaneously, auto-run at application startup creates a race: every pod acquires DATABASECHANGELOGLOCK, one holds it, the rest wait, and if Kubernetes kills a pod mid-migration (because it failed its readiness probe while waiting on the lock), the lock remains set and blocks every subsequent pod. The solution is to run migrations exactly once, before application pods start, using either an init container or a Helm pre-upgrade Job.

Continue reading »

Listeners: Hooking into Job, Step, and Chunk Lifecycle Events

Introduction Spring Batch emits lifecycle events at every stage of execution — before and after a job runs, before and after each step, before and after each chunk, and before and after each individual read/process/write call. Listeners let you hook into these events without modifying your core batch logic. Common uses: Log start/end times and item counts Send success/failure notifications (Slack, email, PagerDuty) Publish metrics to Prometheus or CloudWatch Log every skipped item to a dead-letter table Reset resources before a step begins Listener Hierarchy Job ├── JobExecutionListener beforeJob / afterJob │ └── Step ├── StepExecutionListener beforeStep / afterStep ├── ChunkListener beforeChunk / afterChunk / afterChunkError ├── ItemReadListener beforeRead / afterRead / onReadError ├── ItemProcessListener beforeProcess / afterProcess / onProcessError └── ItemWriteListener beforeWrite / afterWrite / onWriteError └── SkipListener onSkipInRead / onSkipInWrite / onSkipInProcess JobExecutionListener @Component public class ImportJobListener implements JobExecutionListener { private static final Logger log = LoggerFactory.

Continue reading »

MySQL-Specific Patterns: Character Sets, Engines, Large Table Migrations

Liquibase’s change types generate standard SQL. MySQL has quirks — character set requirements that differ from the standard, a storage engine option absent from other databases, row format constraints that affect index key length, and DDL locking behaviour that makes a 10-second table lock acceptable in dev and catastrophic in production. This article covers the MySQL-specific patterns that you will need once you move from tutorial projects to real production databases.

Continue reading »

Preconditions: Guard Your Migrations with tableExists, sqlCheck, and More

A migration assumes the database is in a specific state. It assumes the table it references exists, the column it modifies is the right type, the user running it has the right privileges, and the database is the right engine. When those assumptions are violated — a hotfix was applied manually, a migration ran out of order, someone ran the wrong changelog against the wrong database — the migration fails in a way that can be hard to diagnose.

Continue reading »

Property Substitution: Environment-Specific Values in Changelogs

A changeset that hard-codes the schema name ecommerce works in production but breaks when your staging database is called ecommerce_staging. A changeset that seeds a specific admin email works in dev but shouldn’t run with the same value in staging. Property substitution lets you parameterize these values so one changelog serves every environment. How Property Substitution Works Liquibase replaces ${property-name} tokens in your changelog with the value assigned to that property before executing any SQL.

Continue reading »