Tutorial

264 posts in this section

Pagination and Sorting in Spring Boot

Returning all records from a large table in a single response is a recipe for slow APIs and crashed servers. Pagination is not optional — this article shows how to implement it properly with Spring Data. The Problem with Returning Everything // Never do this for large datasets @GetMapping("/api/orders") public List<Order> getOrders() { return orderRepository.findAll(); // 1 million orders → OutOfMemoryError } Even for “small” tables, always paginate. Requirements change, data grows.

Continue reading »

Password Encoding and User Authentication

Every application needs user registration and login. This article builds a complete authentication system — from storing passwords safely to handling failed login attempts. Never Store Passwords in Plain Text Store a one-way hash, not the password. BCrypt is the industry standard: @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(12); // cost factor 12 → ~250ms per hash on modern hardware // strong enough to slow down brute-force attacks } BCrypt properties:

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 »

Producing and Consuming Kafka Messages

This article implements Kafka producers and consumers with the full production setup — error handling, retries, dead-letter topics, and idempotent consumers. Producer: KafkaTemplate @Service @RequiredArgsConstructor @Slf4j public class OrderEventPublisher { private final KafkaTemplate<String, Object> kafkaTemplate; public void publishOrderCreated(Order order) { OrderCreatedEvent event = new OrderCreatedEvent( order.getId(), order.getCustomerId(), order.getCustomerEmail(), order.getItems().stream().map(OrderItemDto::from).toList(), order.getTotalAmount(), Instant.now() ); // Key = customerId: all events for same customer go to same partition kafkaTemplate.send("order-events", order.getCustomerId().toString(), event) .whenComplete((result, ex) -> { if (ex !

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 »

Reading Flat Files: CSV, Fixed-Width, and Delimited with FlatFileItemReader

Introduction Flat files — CSV exports, fixed-width mainframe feeds, pipe-delimited data dumps — are the most common input source for batch jobs. Spring Batch’s FlatFileItemReader handles all of them. It is restartable out of the box: it persists its line-number position in the ExecutionContext so that a restarted job resumes exactly where it crashed. In this article you will build a complete order-import job that reads a CSV file and inserts rows into a MySQL orders table.

Continue reading »

Reading from External Sources: REST APIs, S3, and Custom ItemReaders

Introduction Not all batch input comes from files or databases. You may need to pull orders from an e-commerce API, sync products from a supplier feed, or process CSV exports stored in Amazon S3. Spring Batch provides MultiResourceItemReader for S3 files and a clean ItemReader interface for anything else. In this article you will build: A custom ItemReader that pages through a REST API An S3 reader that downloads files on demand A composite reader that merges multiple sources into one step The ItemReader Contract The entire ItemReader interface is one method:

Continue reading »

Reading from MySQL: JdbcCursorItemReader and JdbcPagingItemReader

Introduction Most real batch jobs read from a database, not a file. Spring Batch provides two JDBC readers for this: Reader Strategy Thread-safe Use when JdbcCursorItemReader Open a server-side cursor, stream rows No Single-threaded step, huge result sets JdbcPagingItemReader Execute LIMIT / OFFSET queries in a loop Yes Multi-threaded steps, sorted data Both handle restartability automatically and both work with any DataSource — including MySQL. JdbcCursorItemReader How it works The reader opens a single JDBC ResultSet on Step.

Continue reading »

Reading with JPA: JpaPagingItemReader and Entity-Based Reading

Introduction When your application already uses JPA/Hibernate, JpaPagingItemReader lets you read data using JPQL queries and mapped entities instead of raw JDBC. You get the full object graph, type-safe queries, and familiar entity lifecycle — but you also inherit JPA’s pitfalls: the N+1 problem, session-per-read overhead, and first-level cache growth. This article covers: When to choose JpaPagingItemReader over JdbcPagingItemReader Setting up the reader with JPQL and named queries Fetching associations to avoid N+1 Clearing the persistence context to prevent memory leaks A complete order-processing example with MySQL When to Use JpaPagingItemReader Use it when:

Continue reading »

Reliable Event Publishing: The Transactional Outbox Pattern

There is a fundamental problem with publishing Kafka events after a database commit: if the application crashes between the commit and the publish, the event is lost forever. The Transactional Outbox Pattern solves this. The Problem @Transactional public Order createOrder(CreateOrderRequest request) { Order order = orderRepository.save(buildOrder(request)); // DB committed ✓ kafkaTemplate.send("order-events", event); // ← Crash here → event lost, DB already committed // → Inventory never updated, customer never notified return order; } Two distributed systems (PostgreSQL and Kafka) can’t be in a single transaction.

Continue reading »