Tables and columns are straightforward in Liquibase — one change type per operation, automatic rollback, clean history. Stored procedures, views, and triggers are different. They contain body SQL that uses semicolons internally, which conflicts with Liquibase’s default statement splitting. They are replaced rather than altered. And unlike tables, modifying them frequently over time is expected. This article covers the mechanics and patterns that make stored objects manageable in Liquibase. The Core Problem: Delimiter Conflicts A stored procedure body contains semicolons to terminate each statement inside it:
Continue reading »Mysql
80 posts in this section
Tasklets: Running Non-Chunk Operations in Batch Jobs
Introduction Not every step in a batch job reads-processes-writes a stream of items. Sometimes you need to: Delete yesterday’s temp files before reading today’s data Truncate a staging table before loading new data Call a stored procedure to aggregate results Send an email or Slack notification after processing Execute a DDL statement to add an index These operations do not have items — they are single units of work. Spring Batch handles them with the Tasklet interface.
Continue reading »Team Collaboration: Naming Conventions, Conflict Prevention, Git Workflow
A solo developer can treat Liquibase conventions as suggestions. A team of five cannot. When two developers both write “the next migration” on the same day, without a convention that prevents collision, you get duplicate IDs, merge conflicts on the master changelog, or — worst case — two changesets that silently overwrite each other in DATABASECHANGELOG. This article is the operating agreement for teams using Liquibase: what conventions to establish, how to structure the git workflow, what the PR review checklist looks like, and what to do when conflicts happen despite the conventions.
Continue reading »Testing Migrations: H2 vs Testcontainers vs Real MySQL
The CI pipeline from Article 19 validates migrations against a MySQL service container. But that’s not the same as testing that your application code works correctly after the migration runs. This article covers how to structure Spring Boot tests that validate both the migration and the application behaviour — and makes the case for replacing H2 with Testcontainers as your primary testing database. Three Testing Strategies Strategy Database Speed Fidelity Use For H2 in-memory H2 (in-memory) Fastest Low — MySQL-specific SQL fails Unit tests that mock repositories H2 with MySQL mode H2 (MySQL compat) Fast Medium — most SQL works, some quirks Basic integration tests on simple schemas Testcontainers Real MySQL 8.
Continue reading »Testing Spring Batch Jobs: Unit Tests, Integration Tests, and @SpringBatchTest
Introduction Spring Batch jobs are code — they need tests. Without tests you will catch errors in production. With tests you catch them in CI. Spring Batch has a dedicated testing module that provides @SpringBatchTest, JobLauncherTestUtils, and JobRepositoryTestUtils. These tools let you: Run a complete job in a test and assert on its BatchStatus Launch individual steps and inspect StepExecution counters Test readers, processors, and writers in complete isolation This article covers all three levels: unit, integration, and database integration with Testcontainers.
Continue reading »Transforming Data with ItemProcessor: Validation, Filtering, and Enrichment
Introduction ItemProcessor<I, O> sits between the reader and the writer. It receives one item at a time and returns a transformed item — or null to filter the item out entirely. Processors are optional: if your job reads and writes the same type with no transformation needed, you can omit them. The processor interface is one method: public interface ItemProcessor<I, O> { O process(I item) throws Exception; } Return a processed item to pass it to the writer.
Continue reading »Troubleshooting: 10 Common Liquibase Errors and How to Fix Them
Liquibase errors tend to cluster around the same ten problems. You will hit most of them at least once. This article gives you the exact error message to search for, the root cause, and the fastest fix — so you spend minutes recovering, not hours debugging. Error 1: DATABASECHANGELOGLOCK — “Waiting for changelog lock” Symptoms Waiting for changelog lock.... Waiting for changelog lock.... Waiting for changelog lock.... liquibase.exception.LockException: Could not acquire change log lock.
Continue reading »Writing to Files and Databases: FlatFileItemWriter and JdbcBatchItemWriter
Introduction After reading and processing data, your batch job needs to write results somewhere. Spring Batch provides two essential writers: FlatFileItemWriter — writes items to CSV or any delimited/formatted flat file JdbcBatchItemWriter — writes items to a database using JDBC batch inserts/updates Both are transactional and restartable. This article covers both in depth, plus transaction semantics you must understand to avoid duplicates and partial writes. How Writers Work in Spring Batch Writers receive a Chunk<O> — a list of all items processed in the current transaction.
Continue reading »Your First Migration: MySQL Setup and Running liquibase update
You’ve read about changesets, tracking tables, and changelog formats. Now you’re going to run your first real migration against a live MySQL database. By the end of this article you will have connected Liquibase to MySQL, written a changelog that creates the users table for our e-commerce app, previewed the SQL it generates, applied it, and verified the result in the database. This is the article where things become real.
Continue reading »Zero-Downtime Deployments: The Expand-Contract Pattern
A RENAME COLUMN statement takes milliseconds. But if your application is still running the old code when the rename executes, every query that uses the old column name fails immediately. Zero-downtime schema changes are not about making DDL faster — they are about sequencing changes so that no single step breaks the running application. The expand-contract pattern is the standard solution. It breaks dangerous migrations into safe, incremental phases that allow old and new application code to coexist with the same database during deployment.
Continue reading »