Native Queries, Criteria API & Specification API – Complete Guide

 


Native Queries, Criteria API & Specification API – Complete Guide


1. What is a Native Query?

Native Query means:

Writing pure SQL inside JPA.

Example:

@Query(value = "SELECT * FROM user_details WHERE user_name = :name", nativeQuery = true)

Key Characteristics:

  • Direct DB interaction
  • No JPA caching
  • No lazy loading
  • No entity lifecycle management

If DB changes → query breaks.

 


2. When should we use Native Query?

Use Native Query when:

1. Database-specific features

Like:

  • JSONB (Postgres)
  • LATERAL JOIN
  • Window functions

2. Non-entity results

When joining tables without entity relationships.

3. Bulk operations

For high-performance delete/update.

 


3. Full Entity vs Partial Fields

Case 1: Selecting *

SELECT * FROM user_details

JPA auto maps result to Entity.

Case 2: Selecting specific columns

SELECT user_name, phone FROM user_details

JPA fails unless you define mapping.

 


4. Mapping Partial Results (Two Ways)


Method 1: @SqlResultSetMapping (Enterprise Way)

Used when:

  • You want direct DTO output

Steps:

  1. Define @NamedNativeQuery
  2. Define @SqlResultSetMapping
  3. Map columns → DTO constructor

This is best for clean APIs.

 


Method 2: Manual Mapping (Most Used)

Return:

List<Object[]>

Then:

map(obj -> new UserDTO(obj[0], obj[1]))

Simple, fast, flexible.

 


5. Dynamic Native Query

When filters are optional:

WHERE 1=1 
AND name = ?
AND city = ?

Built using:

StringBuilder

Used in:

  • Admin panels
  • Search APIs
  • Reports

 


6. Pagination & Sorting in Native SQL

Using:

LIMIT ? OFFSET ?
ORDER BY column DESC

Handled manually in SQL.

Unlike JPQL, JPA does nothing here.

 


Criteria API – Type Safe Dynamic Queries


7. Why Criteria API exists?

Native SQL:

  • Not portable
  • DB dependent

Criteria API:

  • Type safe
  • DB independent
  • Object oriented

 


8. Core Components

Component Role
CriteriaBuilder Creates queries
CriteriaQuery Defines structure
Root FROM clause
Predicate WHERE condition
TypedQuery Executes

 


9. Criteria Operators

Comparison:

cb.equal()
cb.gt()
cb.lt()

Logical:

cb.and()
cb.or()
cb.not()

String:

cb.like()
cb.notLike()

Collection:

cb.in()
cb.notIn()

 


10. Select vs Multiselect

Method Result
select() Full entity
multiselect() Partial fields

11. Pagination in Criteria

setFirstResult(offset)
setMaxResults(limit)

Manual pagination.

 


Specification API – Cleanest Approach


12. Problems with Criteria API

  1. Too much boilerplate
  2. Duplicate predicate logic
  3. Hard to maintain

13. Specification API Solution

Spring abstraction on Criteria.

You only write:

toPredicate()

Spring handles:

  • Builder
  • Query
  • Execution

 


14. JpaSpecificationExecutor

Gives ready-made methods:

findAll(Specification)
findOne(Specification)
exists(Specification)
findAll(Specification, Pageable)

Reusable, clean, testable.

 


15. Combining Specifications

spec1.and(spec2)
spec1.or(spec2)
Specification.not(spec1)

Perfect for:

  • Search filters
  • Dynamic APIs
  • Admin dashboards

 


Comparison Table

Feature Native Criteria Specification
DB independent ❌ ✅ ✅
Type safe ❌ ✅ ✅
Boilerplate Low High Very low
Maintainability Low Medium High
Performance High Medium Medium
Best for Reports Dynamic queries Real projects

Real Industry Rules (Gold)

These are what architects follow:

  1. Avoid Native unless necessary
  2. Use Specification for search APIs
  3. Use JPQL for joins
  4. Use Native for reports
  5. Always return DTO
  6. Never expose Object[]
  7. Combine Specification with Pageable
  8. Never hardcode SQL in controllers

Interview Killer Lines

Say these and you sound senior:

“Native queries bypass JPA lifecycle.”

“Criteria API is type-safe but verbose.”

“Specification API is abstraction over Criteria.”

“Partial native results require manual mapping.”

“Specification solves code duplication.”


 

Leave a Reply