Hibernate Fetch Types Interview Questions and Answers
Master Hibernate fetching strategies with production-ready interview questions covering LAZY and EAGER loading, select fetching, join fetching, batch fetching, subselect fetching, Entity Graphs, N+1 queries, DTO projections, and senior-level best practices.
Introduction
Fetching defines when and how Hibernate loads entity data and related associations from the database.
A poorly designed fetch strategy can cause:
- N+1 query problems
- Large SQL joins
- Excessive memory usage
- Slow API responses
- Duplicate database rows
LazyInitializationException- Large serialized response payloads
- Unpredictable production performance
Hibernate and JPA provide several mechanisms for controlling fetching:
FetchType.LAZYFetchType.EAGER- Select fetching
- Join fetching
- Batch fetching
- Subselect fetching
- JPQL
JOIN FETCH - Entity Graphs
- DTO projections
A senior developer should not choose fetching based only on annotations. The correct fetch plan depends on the specific business use case, transaction boundary, query shape, data volume, and response requirements.
This guide covers the 15 most frequently asked Hibernate Fetch Types interview questions with production examples, SQL behavior, Mermaid diagrams, common mistakes, and senior-level recommendations.
Q1. What is Fetching in Hibernate?
Answer
Fetching is the process Hibernate uses to load an entity and its associated relationships from the database.
Consider the following relationship:
@Entity
public class Customer {
@Id
private Long id;
private String name;
@OneToMany(
mappedBy = "customer",
fetch = FetchType.LAZY
)
private List<Order> orders = new ArrayList<>();
}
When Hibernate loads a Customer, it must decide whether to load the associated orders immediately or later.
Fetching Questions
Hibernate must answer:
- Should related data load immediately?
- Should related data load only when accessed?
- Should Hibernate use one SQL query or multiple queries?
- Should related rows be loaded in batches?
- Should the association be initialized using a subquery?
Basic Fetch Flow
flowchart TD
A[Application requests Customer] --> B[Hibernate loads Customer]
B --> C{How should Orders be fetched?}
C -->|Lazy| D[Load Customer only]
C -->|Eager| E[Load Customer and Orders immediately]
D --> F[Load Orders later when accessed]
E --> G[Return complete initialized graph]
Why Interviewers Ask This
Fetching is one of the main causes of Hibernate performance problems.
Production Example
A customer summary page may need only the customer's name and email, while an order-history page may need the customer and recent orders together.
Common Mistake
Using one permanent fetch strategy for every use case.
Senior Follow-up
Mappings define default behavior, but production queries should often define a use-case-specific fetch plan.
Q2. What are the main Fetch Types in JPA?
Answer
JPA defines two fetch types:
FetchType.LAZYFetchType.EAGER
LAZY
The association is loaded only when it is accessed.
@OneToMany(
mappedBy = "customer",
fetch = FetchType.LAZY
)
private List<Order> orders;
EAGER
The association must be available immediately after loading the owning entity.
@ManyToOne(fetch = FetchType.EAGER)
private Department department;
Comparison
| LAZY | EAGER |
|---|---|
| Loads association when needed | Loads association immediately |
| Smaller initial query | Larger initial workload |
| Better control | Less control |
| Can cause lazy-loading errors | Can cause over-fetching |
| Common for collections | Default for many to-one in JPA |
Conceptual Behavior
flowchart LR
A[Load Employee] --> B{Fetch Type}
B -->|LAZY| C[Load Employee]
C --> D[Load Department only when accessed]
B -->|EAGER| E[Load Employee and Department immediately]
Common Mistake
Assuming EAGER always means one SQL join.
EAGER specifies when data must be available, not necessarily the exact SQL strategy.
Q3. What are the default Fetch Types in JPA?
Answer
JPA defines different defaults depending on the relationship.
| Relationship | Default Fetch Type |
|---|---|
@OneToOne |
EAGER |
@ManyToOne |
EAGER |
@OneToMany |
LAZY |
@ManyToMany |
LAZY |
@ElementCollection |
LAZY |
Example
@ManyToOne
private Department department;
This is EAGER by default.
@OneToMany(mappedBy = "customer")
private List<Order> orders;
This is LAZY by default.
Why the Defaults Differ
To-one relationships normally reference one row, while collection relationships may contain hundreds or thousands of rows.
flowchart TD
A[Association Type] --> B{Cardinality}
B -->|To-One| C[Default EAGER]
B -->|To-Many| D[Default LAZY]
C --> E[Potential over-fetching]
D --> F[Potential lazy loading or N+1]
Production Recommendation
Explicitly declare fetch types so the mapping intent is clear.
@ManyToOne(fetch = FetchType.LAZY)
private Department department;
Common Mistake
Forgetting that @ManyToOne and @OneToOne are EAGER by default.
Senior Follow-up
Many teams explicitly make to-one associations LAZY and fetch them only when required.
Q4. What is Select Fetching?
Answer
Select Fetching loads related data using a separate SQL query.
Example
Load customer:
SELECT
c.id,
c.name
FROM customers c
WHERE c.id = ?
Later, when customer.getOrders() is accessed:
SELECT
o.id,
o.customer_id,
o.status
FROM orders o
WHERE o.customer_id = ?
Flow
sequenceDiagram
participant App
participant Hibernate
participant DB
App->>Hibernate: find Customer 101
Hibernate->>DB: SELECT customer
DB-->>Hibernate: Customer row
Hibernate-->>App: Customer proxy or entity
App->>Hibernate: customer.getOrders()
Hibernate->>DB: SELECT orders WHERE customer_id = 101
DB-->>Hibernate: Order rows
Hibernate-->>App: Initialized orders collection
Benefits
- Avoids loading unnecessary associations
- Keeps the initial query small
- Works well when associations are rarely accessed
Risks
- Can cause N+1 queries
- Requires an active persistence context for lazy loading
- Adds database round trips
Production Example
A customer list page shows only customer names, so orders should not load for every customer.
Common Mistake
Using Select Fetching for many parent rows and then accessing each child collection individually.
Q5. What is Join Fetching?
Answer
Join Fetching loads an entity and its association using a SQL join.
JPQL Example
List<Customer> customers = entityManager
.createQuery(
"""
select distinct c
from Customer c
left join fetch c.orders
where c.active = true
""",
Customer.class
)
.getResultList();
SQL Concept
SELECT
c.id,
c.name,
o.id,
o.status
FROM customers c
LEFT JOIN orders o
ON o.customer_id = c.id
WHERE c.active = true
Flow
flowchart TD
A[Application executes JOIN FETCH query] --> B[Hibernate builds one SQL join]
B --> C[Database returns customer and order rows]
C --> D[Hibernate reconstructs Customer entities]
D --> E[Orders collection initialized]
Benefits
- Avoids N+1 queries
- Loads required graph in one round trip
- Useful for detail pages
Risks
- Duplicate parent rows
- Large result sets
- Pagination problems
- Cartesian explosion with multiple collections
Common Mistake
Join fetching multiple large collections in one query.
Senior Follow-up
Join fetching is best when the result graph is bounded and the association is definitely required.
Q6. What is Batch Fetching?
Answer
Batch Fetching allows Hibernate to initialize multiple lazy associations using a smaller number of queries.
Instead of executing one query per parent, Hibernate loads associations for several parent IDs together.
Without Batch Fetching
SELECT customer
SELECT orders for customer 1
SELECT orders for customer 2
SELECT orders for customer 3
With Batch Fetching
SELECT
o.*
FROM orders o
WHERE o.customer_id IN (?, ?, ?)
Annotation Example
@OneToMany(
mappedBy = "customer",
fetch = FetchType.LAZY
)
@BatchSize(size = 50)
private List<Order> orders;
Global Configuration
spring.jpa.properties.hibernate.default_batch_fetch_size=50
Flow
flowchart TD
A[Load 100 Customers] --> B[Orders remain lazy]
B --> C[Access first Orders collection]
C --> D[Hibernate collects multiple Customer IDs]
D --> E[Execute WHERE customer_id IN batch]
E --> F[Initialize multiple collections]
Benefits
- Reduces N+1 query count
- Avoids very large join results
- Works well with lazy loading
Risks
- Still requires multiple SQL queries
- Batch size must be tuned
- Large
INclauses may affect database performance
Production Example
Loading 100 employees and their departments using batches of 25.
Common Mistake
Assuming batch fetching converts all access into one query.
Q7. What is Subselect Fetching?
Answer
Subselect Fetching loads multiple collections using a secondary query based on the original parent query.
Example Parent Query
SELECT
c.id,
c.name
FROM customers c
WHERE c.active = true
Collection Query
SELECT
o.*
FROM orders o
WHERE o.customer_id IN (
SELECT c.id
FROM customers c
WHERE c.active = true
)
Hibernate Mapping
@OneToMany(mappedBy = "customer")
@Fetch(FetchMode.SUBSELECT)
private List<Order> orders;
Flow
sequenceDiagram
participant App
participant Hibernate
participant DB
App->>Hibernate: Load active Customers
Hibernate->>DB: SELECT active customers
DB-->>Hibernate: Customer rows
App->>Hibernate: Access one orders collection
Hibernate->>DB: SELECT orders using original customer subselect
DB-->>Hibernate: Orders for all loaded customers
Hibernate-->>App: Multiple collections initialized
Benefits
- Reduces N+1 queries
- Can initialize many collections efficiently
- Avoids duplicate parent rows from join fetching
Risks
- May load more collections than needed
- Depends on the original query shape
- Can produce expensive subqueries
Common Mistake
Using subselect fetching for very large parent result sets.
Q8. What is the difference between Fetch Type and Fetch Strategy?
Answer
Fetch Type determines when an association should be loaded.
Fetch Strategy determines how Hibernate loads it.
Fetch Type
- LAZY
- EAGER
Fetch Strategy
- SELECT
- JOIN
- BATCH
- SUBSELECT
Comparison
| Concept | Question Answered |
|---|---|
| Fetch Type | When should data be initialized? |
| Fetch Strategy | Which SQL approach should load it? |
Diagram
flowchart TD
A[Association Fetching] --> B[Fetch Type]
A --> C[Fetch Strategy]
B --> D[LAZY]
B --> E[EAGER]
C --> F[SELECT]
C --> G[JOIN]
C --> H[BATCH]
C --> I[SUBSELECT]
Example
An association may be:
LAZY + SELECT
or:
LAZY + BATCH
An EAGER association may still be loaded through separate SQL statements.
Common Mistake
Saying EAGER and JOIN are the same.
Senior Follow-up
Annotations provide defaults, while queries and Entity Graphs often determine the runtime fetch strategy.
Q9. What is the N+1 Query Problem?
Answer
The N+1 problem occurs when Hibernate executes:
- One query to load parent entities
- One additional query for each parent association
Example
List<Customer> customers =
entityManager
.createQuery(
"select c from Customer c",
Customer.class
)
.getResultList();
for (Customer customer : customers) {
System.out.println(
customer.getOrders().size()
);
}
SQL Pattern
1 query to load Customers
+
N queries to load Orders
=
N + 1 queries
Mermaid Diagram
sequenceDiagram
participant App
participant Hibernate
participant DB
App->>Hibernate: Load all Customers
Hibernate->>DB: SELECT customers
DB-->>Hibernate: 100 customers
loop For each Customer
App->>Hibernate: Access orders
Hibernate->>DB: SELECT orders for customer
DB-->>Hibernate: Orders
end
Impact
- High database round trips
- Increased latency
- More database CPU
- Poor scalability
- Slow APIs
Common Solutions
JOIN FETCH- Entity Graphs
- Batch fetching
- DTO projections
- Query redesign
Common Mistake
Trying to solve N+1 by making the relationship permanently EAGER.
Senior Follow-up
The best solution depends on result size, pagination, data volume, and whether the association is needed.
Q10. How does JOIN FETCH solve N+1 queries?
Answer
JOIN FETCH tells Hibernate to load an association as part of the main query.
Example
List<Customer> customers =
entityManager
.createQuery(
"""
select distinct c
from Customer c
left join fetch c.orders
""",
Customer.class
)
.getResultList();
Query Comparison
Without Join Fetch
SELECT customers
SELECT orders for customer 1
SELECT orders for customer 2
SELECT orders for customer 3
With Join Fetch
SELECT customers LEFT JOIN orders
Diagram
flowchart LR
A[Customer Query] --> B[JOIN FETCH Orders]
B --> C[Single SQL Query]
C --> D[Customers and Orders initialized]
Why distinct Is Often Used
One customer may appear in several SQL rows because each order produces another joined row.
Customer 1 + Order A
Customer 1 + Order B
Customer 1 + Order C
Hibernate reconstructs one customer object, but JPQL distinct helps remove duplicate root results.
Risks
- Large joined result
- Pagination may become incorrect
- Multiple collections can create Cartesian products
Common Mistake
Using collection fetch joins together with page-level pagination.
Q11. What is an Entity Graph?
Answer
An Entity Graph defines which associations should be fetched for a specific query without permanently changing entity mappings.
Named Entity Graph Example
@Entity
@NamedEntityGraph(
name = "Customer.withOrders",
attributeNodes = {
@NamedAttributeNode("orders")
}
)
public class Customer {
}
Repository Example
@EntityGraph(
value = "Customer.withOrders"
)
Optional<Customer> findById(Long id);
Dynamic Entity Graph
EntityGraph<Customer> graph =
entityManager.createEntityGraph(
Customer.class
);
graph.addAttributeNodes("orders");
Map<String, Object> hints = Map.of(
"jakarta.persistence.fetchgraph",
graph
);
Customer customer =
entityManager.find(
Customer.class,
customerId,
hints
);
Flow
flowchart TD
A[Repository Query] --> B[Apply Entity Graph]
B --> C[Select Required Associations]
C --> D[Hibernate Builds Fetch Plan]
D --> E[Return Initialized Graph]
Benefits
- Query-specific fetch plans
- Avoids permanent EAGER mappings
- Reusable
- Works well with Spring Data JPA
Common Mistake
Creating one very large graph for all application use cases.
Senior Follow-up
Use small, use-case-specific Entity Graphs.
Q12. What are DTO Projections and how do they help fetching?
Answer
DTO projections retrieve only the columns required by the use case instead of loading full managed entities.
DTO
public record CustomerOrderSummary(
Long customerId,
String customerName,
Long orderCount
) {
}
JPQL Projection
List<CustomerOrderSummary> summaries =
entityManager
.createQuery(
"""
select new com.codewithvenu.CustomerOrderSummary(
c.id,
c.name,
count(o.id)
)
from Customer c
left join c.orders o
group by c.id, c.name
""",
CustomerOrderSummary.class
)
.getResultList();
Diagram
flowchart TD
A[API requires customer summary] --> B[DTO Projection Query]
B --> C[Select only required columns]
C --> D[No full entity graph]
D --> E[Smaller response and lower memory use]
Benefits
- Avoids lazy-loading problems
- Reduces selected columns
- Avoids persistence-context overhead
- Works well for reports and API responses
- Prevents accidental serialization of entity graphs
Limitations
- DTOs are not managed entities
- No dirty checking
- Separate query design required
Common Mistake
Loading full entities and converting them into DTOs after unnecessary associations have already been fetched.
Q13. What are common Fetching interview mistakes?
Answer
Common mistakes include:
- Using EAGER for every association.
- Making collections EAGER.
- Ignoring N+1 queries.
- Using
JOIN FETCHfor multiple large collections. - Combining collection fetch joins with pagination.
- Accessing lazy associations outside a transaction.
- Returning entities directly from REST controllers.
- Assuming LAZY always avoids SQL.
- Assuming EAGER always uses one query.
- Ignoring generated SQL.
- Loading entire entity graphs for summary pages.
- Using Open Session in View to hide poor fetch design.
- Selecting very large batch sizes.
- Using Entity Graphs without understanding query impact.
- Confusing fetch type with fetch strategy.
Dangerous Example
@OneToMany(
mappedBy = "customer",
fetch = FetchType.EAGER
)
private List<Order> orders;
If every customer has thousands of orders, every customer load becomes expensive.
Q14. Give a production Fetch Strategy example.
Scenario
An e-commerce system supports:
- Customer list page
- Customer detail page
- Customer order summary
- Batch export
Each use case needs a different fetch plan.
Customer List Page
Need:
- ID
- Name
Recommended:
DTO projection
Customer Detail Page
Need:
- Customer
- Primary address
- Recent orders
Recommended:
Entity Graph or controlled JOIN FETCH
Order Summary
Need:
- Customer name
- Order count
- Total value
Recommended:
Aggregate DTO query
Batch Export
Need:
- Large row set
- Limited memory usage
Recommended:
Streaming query + DTO projection
Architecture
flowchart TD
A[Customer Use Cases] --> B[List Page]
A --> C[Detail Page]
A --> D[Summary Report]
A --> E[Batch Export]
B --> F[DTO Projection]
C --> G[Entity Graph]
D --> H[Aggregate Query]
E --> I[Streaming DTO Query]
Example Service
@Transactional(readOnly = true)
public CustomerDetailsResponse getCustomer(
Long customerId
) {
Customer customer =
customerRepository
.findWithOrdersById(customerId)
.orElseThrow(
CustomerNotFoundException::new
);
return customerMapper.toDetails(customer);
}
Common Mistake
Trying to serve all four use cases using one entity-loading method.
Senior Follow-up
Fetch plans should be aligned to API response contracts and business workflows.
Q15. What are senior-level Hibernate Fetching best practices?
Answer
Senior developers should treat fetch planning as a query-design responsibility.
Best Practices
- Default collections to LAZY.
- Consider LAZY for to-one relationships.
- Fetch associations only when required.
- Use DTO projections for read-only screens.
- Use
JOIN FETCHfor bounded detail queries. - Use Entity Graphs for reusable query-specific fetch plans.
- Use batch fetching to reduce N+1 queries.
- Use subselect fetching selectively.
- Avoid multiple collection fetch joins.
- Avoid collection fetch joins with pagination.
- Review generated SQL.
- Monitor query count and latency.
- Keep transaction boundaries clear.
- Do not expose entities directly through APIs.
- Load test with production-scale relationship sizes.
Decision Flow
flowchart TD
A[Does the use case need related data?] -->|No| B[Keep association LAZY]
A -->|Yes| C{How much related data?}
C -->|Small and bounded| D[JOIN FETCH or Entity Graph]
C -->|Many parents| E[Batch Fetching]
C -->|Summary fields only| F[DTO Projection]
C -->|Large reporting data| G[Dedicated query or streaming DTO]
Production Checklist
Understand Use Case
│
▼
Estimate Data Volume
│
▼
Select Fetch Plan
│
▼
Review Generated SQL
│
▼
Test Pagination
│
▼
Measure Query Count
│
▼
Load Test
│
▼
Monitor Production
Senior Follow-up
The safest default is not "always LAZY" or "always EAGER." It is explicit, use-case-driven fetching.
Hibernate Fetching Architecture
flowchart TD
A[Application Service] --> B[Repository Query]
B --> C[Hibernate Fetch Plan]
C --> D{Strategy}
D --> E[SELECT]
D --> F[JOIN]
D --> G[BATCH]
D --> H[SUBSELECT]
E --> I[Database]
F --> I
G --> I
H --> I
I --> J[Entity or DTO Result]
LAZY Fetching Lifecycle
sequenceDiagram
participant Service
participant Hibernate
participant Database
Service->>Hibernate: Load Customer
Hibernate->>Database: SELECT Customer
Database-->>Hibernate: Customer row
Hibernate-->>Service: Customer with lazy Orders
Service->>Hibernate: Access Orders
Hibernate->>Database: SELECT Orders
Database-->>Hibernate: Order rows
Hibernate-->>Service: Initialized Orders
EAGER Fetching Lifecycle
sequenceDiagram
participant Service
participant Hibernate
participant Database
Service->>Hibernate: Load Customer
Hibernate->>Database: Load Customer and required eager associations
Database-->>Hibernate: Customer and association data
Hibernate-->>Service: Fully initialized required graph
N+1 Query Problem
flowchart TD
A[Load 100 Customers] --> B[1 Customer Query]
B --> C[Loop through Customers]
C --> D[Load Orders for Customer 1]
C --> E[Load Orders for Customer 2]
C --> F[Load Orders for Customer N]
D --> G[Total Queries = 1 + N]
E --> G
F --> G
N+1 Solutions
flowchart LR
A[N+1 Query Problem] --> B[JOIN FETCH]
A --> C[Entity Graph]
A --> D[Batch Fetching]
A --> E[DTO Projection]
A --> F[Query Redesign]
Fetch Type vs Strategy
| Fetch Type | Purpose |
|---|---|
| LAZY | Load when accessed |
| EAGER | Load immediately |
| Fetch Strategy | SQL Behavior |
|---|---|
| SELECT | Separate query |
| JOIN | SQL join |
| BATCH | Load multiple IDs together |
| SUBSELECT | Reuse parent query as subselect |
Fetch Strategy Comparison
| Strategy | Query Count | Main Benefit | Main Risk |
|---|---|---|---|
| Select | Potentially many | Small initial query | N+1 |
| Join | Usually one | Fewer round trips | Large duplicate result |
| Batch | Several controlled queries | Reduces N+1 | Large IN clauses |
| Subselect | Usually two | Loads multiple collections | Over-fetching |
| DTO Projection | Usually one | Minimal data | Not managed |
| Entity Graph | Depends | Flexible fetch plan | Can become too broad |
Pagination Warning
flowchart TD
A[Paginated Customer Query] --> B[JOIN FETCH Orders Collection]
B --> C[SQL returns duplicate Customer rows]
C --> D[Database pagination applies to rows]
D --> E[Incorrect or incomplete page]
For paginated collection results, consider:
- Page parent IDs first.
- Fetch associations in a second query.
- Use DTO projections.
- Use batch fetching.
Two-Step Pagination Pattern
sequenceDiagram
participant App
participant Hibernate
participant DB
App->>Hibernate: Request page of Customer IDs
Hibernate->>DB: SELECT customer IDs with LIMIT/OFFSET
DB-->>Hibernate: Page of IDs
Hibernate->>DB: SELECT Customers and Orders WHERE ID IN (...)
DB-->>Hibernate: Complete graph for page
Hibernate-->>App: Stable paginated result
Multiple Collection Join Risk
Assume:
- One customer has 10 orders.
- The same customer has 5 addresses.
Joining both collections may produce:
10 × 5 = 50 SQL rows
flowchart LR
A[Customer] --> B[10 Orders]
A --> C[5 Addresses]
B --> D[Cartesian Product]
C --> D
D --> E[50 Joined Rows]
This increases:
- Network traffic
- Memory use
- Result processing time
- Duplicate data
Entity Graph Example
@Entity
@NamedEntityGraph(
name = "Order.withCustomerAndItems",
attributeNodes = {
@NamedAttributeNode("customer"),
@NamedAttributeNode("items")
}
)
public class Order {
@Id
private Long id;
@ManyToOne(fetch = FetchType.LAZY)
private Customer customer;
@OneToMany(
mappedBy = "order",
fetch = FetchType.LAZY
)
private List<OrderItem> items;
}
Spring Data Repository Example
public interface OrderRepository
extends JpaRepository<Order, Long> {
@EntityGraph(
value = "Order.withCustomerAndItems"
)
Optional<Order> findDetailedById(Long id);
}
Batch Fetching Example
@Entity
public class Customer {
@OneToMany(
mappedBy = "customer",
fetch = FetchType.LAZY
)
@BatchSize(size = 25)
private List<Order> orders =
new ArrayList<>();
}
DTO Projection Example
public record OrderListItem(
Long orderId,
String customerName,
String status,
BigDecimal total
) {
}
List<OrderListItem> orders =
entityManager.createQuery(
"""
select new com.codewithvenu.OrderListItem(
o.id,
o.customer.name,
o.status,
o.total
)
from Order o
where o.status = :status
order by o.createdAt desc
""",
OrderListItem.class
)
.setParameter(
"status",
OrderStatus.COMPLETED
)
.getResultList();
Production Fetch Decision Matrix
| Use Case | Recommended Fetching |
|---|---|
| Customer list | DTO projection |
| Customer detail | Entity Graph |
| Order with items | Join fetch if bounded |
| Paginated customers | Page IDs + second query |
| Large collection access | Batch fetch |
| Report | Aggregate DTO query |
| Batch export | Streaming DTO query |
| Single reference entity | Lazy to-one or explicit fetch |
| Multiple large collections | Separate queries |
| REST response | DTO, not entity graph |
Common SQL Patterns
Select Fetch
SELECT * FROM customers WHERE id = ?;
SELECT * FROM orders WHERE customer_id = ?;
Join Fetch
SELECT
c.*,
o.*
FROM customers c
LEFT JOIN orders o
ON o.customer_id = c.id
WHERE c.id = ?;
Batch Fetch
SELECT *
FROM orders
WHERE customer_id IN (?, ?, ?, ?);
Aggregate DTO Query
SELECT
c.id,
c.name,
COUNT(o.id)
FROM customers c
LEFT JOIN orders o
ON o.customer_id = c.id
GROUP BY c.id, c.name;
Interview Quick Revision
| Concept | Purpose |
|---|---|
| Fetching | Controls association loading |
| LAZY | Load when accessed |
| EAGER | Load immediately |
| Select Fetch | Separate SQL query |
| Join Fetch | Load using SQL join |
| Batch Fetch | Load multiple associations together |
| Subselect Fetch | Load collections using parent subquery |
| N+1 Problem | One parent query plus N child queries |
JOIN FETCH |
Query-level association loading |
| Entity Graph | Reusable runtime fetch plan |
| DTO Projection | Load only required fields |
@BatchSize |
Configure batch association loading |
| Cartesian Product | Duplicate rows from multiple joins |
| Pagination | Requires careful collection fetching |
| Generated SQL | Must be reviewed and measured |
Key Takeaways
- Hibernate fetching determines when and how entities and relationships are loaded.
- JPA provides LAZY and EAGER fetch types.
- To-one relationships are EAGER by default, while to-many relationships are LAZY by default.
- Fetch Type defines when data is needed, while Fetch Strategy defines how SQL loads it.
- Select fetching is simple but can cause N+1 queries.
- Join fetching reduces round trips but may create large duplicate result sets.
- Batch fetching loads multiple associations using
INqueries and is useful for reducing N+1 problems. - Subselect fetching can initialize collections for multiple parents using a secondary query.
JOIN FETCHshould be used carefully with collections and pagination.- Entity Graphs provide use-case-specific fetch plans without permanently changing mappings.
- DTO projections are ideal for read-only API responses, reports, and summary pages.
- Making every relationship EAGER is not a valid solution to N+1 queries.
- Multiple collection fetch joins can create Cartesian products and severe performance problems.
- Fetch plans should be designed around specific business use cases and expected data volume.
- Senior developers validate fetch decisions by reviewing SQL, measuring query counts, load testing, and monitoring production latency.