Dynamic SQL Queries with Spring Data JPA in 6 Minutes

 

Transcript:

Let’s see how we can create dynamic SQL queries with Spring Data JPA

We will use a small demo bookshop. The main entity class is Book. We also have Format Category Language and Author classes

In a real world bookshop application users apply multiple filters to find the books they need Writing separate queries for every combination is not practical This is where dynamic SQL queries become useful

Dynamic queries allow us to build SQL statements based on user input at runtime

To implement this with JPA we use the Specification interface It allows us to build predicates over an entity and combine them into flexible WHERE clauses

To enable this we extend the repository with JpaSpecificationExecutor

Then we create a BookSpecification class where we define reusable specifications for Book

We start with a category filter First we check if the input is null or empty If it is we skip applying the filter

Specification.unrestricted represents a neutral condition It does not affect the query Think of it as match everything and do not add any WHERE condition This is useful for optional filters

A Specification is a function that Spring Data JPA uses when building a query It receives root query and CriteriaBuilder

Root represents the entity being queried in this case Book CriteriaBuilder is used to create conditions called predicates Query represents the overall query structure but is not always needed for simple cases

The method returns a Predicate

In our case we create a simple equality condition using CriteriaBuilder The query parameter is not used here which is fine It is only needed for more advanced cases like joins or query modifications

However using field names as strings is fragile If a field name changes the code breaks at runtime

To solve this we use the JPA static metamodel for type safe queries

We enable this by adding the Hibernate annotation processor in Maven and running Maven clean compile The metamodel is generated in the target generated sources directory

Now we can use the generated Book_ class instead of strings This gives compile time safety If a field is renamed the code fails at compile time instead of runtime

Next we create additional filters in the same way for language format and price Each filter returns a Specification of Book

Then we create a withFilters method which acts as a composer It does not define a condition itself but combines multiple specifications into one

Specifications are combined using logical AND Empty filters are ignored thanks to unrestricted

In the service layer we create a findAllFiltered method that accepts category language format and maximum price

Inside the method we build a combined specification pass it to bookRepository findAll and Spring Data JPA converts it into a SQL query and executes it

Finally we test the implementation using test data loaded from data sql Since we use H2 database there is no need for Testcontainers only Spring Boot test annotation is required

This is how you build type safe dynamic SQL queries with Spring Data JPA

Summary

This video explains how to build dynamic SQL queries in Spring Data JPA using the Specification API. It shows how to avoid writing multiple static queries by combining optional filters such as category, language, format, and price into a single flexible query. The approach uses Specifications to build reusable predicates and then composes them into a final query using logical operations. It also introduces the JPA static metamodel for type-safe queries, preventing runtime errors caused by string-based field references. Finally, it demonstrates how the service layer executes the combined specification and returns filtered results through Spring Data JPA.

About Catherine

Java developer passionate about Spring Boot. Writer. Developer Advocate at BellSoft

Social Media

Videos
card image
Mar 26, 2026
Java Developer Roadmap 2026: From Basics to Production

Most Java roadmaps teach tools. This one teaches order — the only thing that actually gets you to production. You don’t need to learn everything. You need to learn the right things, in the right sequence. In this video, we break down a practical Java developer roadmap for 2026 — from syntax and OOP to Spring, databases, testing, and deployment. Structured into 8 levels, it shows how real engineers grow from fundamentals to production-ready systems. We cover what to learn and what to ignore: core Java, collections, streams, build tools, Git, SQL and JDBC before Hibernate, the Spring ecosystem, testing with JUnit, and deployment with Docker and CI/CD. You’ll also understand why most developers get stuck — jumping into frameworks too early, skipping SQL, or treating tools as knowledge. This roadmap gives you a clear path into real-world Java development — with priorities, trade-offs, and production context.

Videos
card image
Mar 19, 2026
TOP-5 Lightweight Linux Distributions for Containers

In this video, we compare five lightweight Linux distributions commonly used as base images: Alpine, Alpaquita, Chiseled Ubuntu, RHEL UBI Micro, and Wolfi. There are no rankings or recommendations — just a structured look at how these distros differ so you can evaluate them in your own context.

Further watching

Videos
card image
Apr 30, 2026
Java Flight Recorder Tutorial: How to Profile Java Applications

High CPU, GC spikes, or slow startup are common production issues, but logs and metrics don’t always reveal what the JVM is actually doing. Java Flight Recorder (JFR) provides a precise, low-overhead view of JVM behavior, safe for use even in production environments. In this video, you’ll learn how to use JFR to identify real bottlenecks such as CPU hotspots, memory allocation pressure, thread contention, and I/O stalls. We walk through the full workflow, including starting recordings with JVM flags, controlling them via jcmd, running JFR inside Docker containers, and attaching to live systems using ephemeral containers. Then we analyze a real Spring Boot recording in JDK Mission Control, breaking down GC behavior, allocation patterns, thread states, and method-level hotspots. If you want to move from symptoms to root cause with more confidence, this approach will help. Full article with commands and examples: [https://bell-sw.com/blog/how-to-profile-java-applications-with-jfr-beginner-s-guide/](https://bell-sw.com/blog/how-to-profile-java-applications-with-jfr-beginner-s-guide/)

Videos
card image
Apr 8, 2026
Best Oracle Java Alternatives in 2026 Comparison of OpenJDK Distributions

A comparison of major OpenJDK distributions (Temurin, Liberica, Zulu, Corretto, Semeru, etc.), covering who maintains them, how updates are delivered, and what lifecycle guarantees they provide. We also explain why upstream OpenJDK isn’t production-ready and how your vendor choice impacts real-world systems. Useful for Spring Boot, containers, and Kubernetes to avoid hidden risks and choose the right runtime.

Videos
card image
Apr 2, 2026
Java Memory Options You Need in Production

JVM memory tuning can be tricky. Teams increase -Xmx and assume the problem is solved. Then the app still hits OOM. Because maximum heap size is not the only thing that affects memory footprint. The JVM uses RAM for much more than heap: metaspace, thread stacks, JIT/code cache, direct buffers, and native allocations. That’s why your process can run out of memory while heap still looks “fine”. In this video, we break down how JVM memory actually works and how to control it with a minimal, production-safe set of flags. We cover heap sizing (-Xms, -Xmx), dynamic resizing, direct memory (-XX:MaxDirectMemorySize), and total RAM limits (-XX:MaxRAMPercentage) — especially in containerized environments like Docker and Kubernetes. We also explain GC choices such as G1, ZGC, and Shenandoah, when defaults are enough, and why GC logging (-Xlog:gc*) is mandatory before tuning. Finally, we show how to diagnose failures with heap dumps and OOM hooks. This is not about adding more flags. It’s about understanding what actually consumes memory — and making decisions you can justify in production.