Creating SQL Queries Dynamically in Spring Boot!

Learner, Love to make things simple, Full Stack Developer, StackOverflower, Passionate about using machine learning, deep learning and AI
Search for a command to run...

Learner, Love to make things simple, Full Stack Developer, StackOverflower, Passionate about using machine learning, deep learning and AI
No comments yet. Be the first to comment.
Spring Boot tutorials, java and spring cloud tutorials where we can cover other parts like microservices, etc.
Spring Data REST simplifies the creation of RESTful APIs for Spring Data repositories. It eliminates boilerplate code and automatically exposes repository methods as REST endpoints. This guide demonstrates how to create a Spring Data REST application...
Move beyond traditional RESTful thinking. Learn how to design APIs specifically for MCP (Model Context Protocol) servers. This guide covers the shift in mindset, a practical OpenAPI 3.1 example, and a Spring Boot implementation to make your services ...

Extending Kestra to Every Corner of Your Data Stack. Introduction: The Power of Plugins Imagine you're a master chef. You don't just have one knife - you have specialized tools for every task: a paring knife for delicate work, a chef's knife for chop...
Mastering Complex Orchestration Scenarios. Introduction: The Orchestrator's Toolkit Imagine you're conducting a symphony. You don't just wave your baton - you cue sections, adjust tempo, handle surprises, and ensure harmony. That's what advanced work...
From Data Extraction to Loading - A Practical Guide Introduction: Why ETL Still Matters in the Modern Data Stack Remember when data engineering was "extract, transform, load"? Some say ETL is dead, replaced by ELT, reverse ETL, and data mesh. But her...
Building Blocks of Declarative Orchestration. Introduction: The Power of Simplicity Imagine trying to build a house without understanding bricks, beams, and blueprints. That's what using an orchestration tool without understanding its core concepts f...
Working with databases is a fundamental part of developing most applications, but sometimes, static SQL queries don’t meet the dynamic requirements of real-world applications. For example, what if you need to build a search feature that filters results based on multiple criteria, where not all fields are mandatory? Enter Spring Data JPA Specifications, a powerful tool for creating dynamic and type-safe SQL queries.
In this article, we’ll explore how to use Spring Data JPA Specification to craft flexible SQL queries programmatically without getting bogged down by boilerplate code. By the end, you’ll have a clear understanding and a practical example to get started.
Static SQL queries are straightforward and often sufficient for simple use cases. However, in scenarios where:
Query parameters are conditional (e.g., a search form where users can filter by name, age, or city, or none at all).
You need to construct queries dynamically at runtime based on user input.
Static queries become rigid and unmanageable, leading to cluttered, error-prone code. Dynamic SQL queries solve this by building SQL statements programmatically.
Spring Data JPA’s Specification interface provides a clean and type-safe way to create dynamic queries. It allows you to define predicates (conditions) that combine dynamically at runtime, depending on the input.
Here’s the high-level approach:
Use Specification to define query conditions programmatically.
Combine these conditions dynamically based on input.
Pass the Specification to your repository to execute the query.
Let’s build an example of a Customer search feature where users can filter results by name, email, or city.
Ensure your Spring Boot project has the following dependencies in pom.xml:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
Note: We’re using the H2 database for simplicity, but you can replace it with any database of your choice.
Here’s our Customer entity:
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
@Entity
public class Customer {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private String email;
private String city;
// Getters and Setters
}
The repository should extend JpaSpecificationExecutor to enable Specification-based queries:
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
public interface CustomerRepository extends JpaRepository<Customer, Long>, JpaSpecificationExecutor<Customer> {
}
The core logic for building dynamic queries goes into the Specification implementation:
import org.springframework.data.jpa.domain.Specification;
import org.springframework.util.StringUtils;
public class CustomerSpecifications {
public static Specification<Customer> hasName(String name) {
return (root, query, criteriaBuilder) ->
StringUtils.hasText(name) ? criteriaBuilder.equal(root.get("name"), name) : null;
}
public static Specification<Customer> hasEmail(String email) {
return (root, query, criteriaBuilder) ->
StringUtils.hasText(email) ? criteriaBuilder.equal(root.get("email"), email) : null;
}
public static Specification<Customer> hasCity(String city) {
return (root, query, criteriaBuilder) ->
StringUtils.hasText(city) ? criteriaBuilder.equal(root.get("city"), city) : null;
}
}
Combine the conditions dynamically in the service layer based on user input:
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class CustomerService {
private final CustomerRepository customerRepository;
public CustomerService(CustomerRepository customerRepository) {
this.customerRepository = customerRepository;
}
public List<Customer> searchCustomers(String name, String email, String city) {
Specification<Customer> spec = Specification
.where(CustomerSpecifications.hasName(name))
.and(CustomerSpecifications.hasEmail(email))
.and(CustomerSpecifications.hasCity(city));
return customerRepository.findAll(spec);
}
}
Finally, expose this search functionality via a REST API:
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RestController
public class CustomerController {
private final CustomerService customerService;
public CustomerController(CustomerService customerService) {
this.customerService = customerService;
}
@GetMapping("/customers/search")
public List<Customer> searchCustomers(
@RequestParam(required = false) String name,
@RequestParam(required = false) String email,
@RequestParam(required = false) String city) {
return customerService.searchCustomers(name, email, city);
}
}
Start the application and access the H2 Console at http://localhost:8080/h2-console.
Insert some test data:
INSERT INTO CUSTOMER (NAME, EMAIL, CITY) VALUES
('John Doe', 'john@example.com', 'New York'),
('Jane Smith', 'jane@example.com', 'Los Angeles'),
('Alice Johnson', 'alice@example.com', 'New York');
Test the API using Postman or curl:
Filter by city:
GET /customers/search?city=New York
Filter by name and email:
GET /customers/search?name=John Doe&email=john@example.com
Simplicity: Spring Data JPA Specification eliminates the need for writing raw SQL queries.
Flexibility: Conditions are dynamically combined, making it ideal for scenarios with optional filters.
Scalability: Add more fields or filters easily by creating new Specification methods.
Dynamic SQL queries can greatly simplify the handling of complex and flexible database requirements. Using Spring Data JPA Specifications, we crafted dynamic and type-safe queries programmatically. This approach not only reduces boilerplate code but also makes your application more adaptable to future changes.
Experiment with this example in your projects and see how it transforms your database interactions!
More such articles:
https://www.youtube.com/@maheshwarligade