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.LAZY
  • FetchType.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.LAZY
  • FetchType.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 IN clauses 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 FETCH for 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
  • Email

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 FETCH for 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:

  1. Page parent IDs first.
  2. Fetch associations in a second query.
  3. Use DTO projections.
  4. 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 IN queries and is useful for reducing N+1 problems.
  • Subselect fetching can initialize collections for multiple parents using a secondary query.
  • JOIN FETCH should 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.