Java.Hibernate.Middle.What are batch fetching and how do you enable it?

batch fetching is a great way to avoid the N+1 problem without forcing eager loading. Let’s break it down clearly:

🔎 What is batch fetching?

When you use lazy loading, Hibernate loads collections or associated entities on demand — but by default, it issues 1 query per entity → classic N+1 problem.

Batch fetching lets Hibernate load multiple entities or collections in batches when one is accessed, reducing the number of queries.

For example:

  • Without batch fetching: loading 100 lazy Author.books → 100 separate queries.
  • With batch fetching size 10: loading those 100 → only ~10 queries (each loads 10 collections at once).

✅ How to enable batch fetching

You do it in your entity mappings using Hibernate’s @BatchSize annotation or globally in configuration:

1️⃣ Per-association: @BatchSize

For an entity or collection field:

@Entity
public class Author {
    @OneToMany(mappedBy = "author", fetch = FetchType.LAZY)
    @BatchSize(size = 10) // Hibernate will load books for 10 authors at once
    private List<Book> books;
}

Or on an entity to affect all its lazy references:

@Entity
@BatchSize(size = 10)
public class Book {
    // ...
}

2️⃣ Global setting: Hibernate property

If you want batch fetching to apply to all lazy associations in your app, set in your config (e.g., application.properties):

spring.jpa.properties.hibernate.default_batch_fetch_size=10

Or directly in Hibernate:

hibernate.default_batch_fetch_size=10

🚨 Important notes:

Batch fetching ≠ eager fetching — it keeps associations lazy, but batches the loads when needed.
✔ Works only if you access multiple lazy proxies of the same type in the same session.
✔ Doesn’t change JPQL behavior — it applies when Hibernate resolves proxies or collections.
✔ Very helpful for reducing query count in web pages/tables showing multiple entities with lazy fields.

🔎 Example:
You load 20 authors, then access author.getBooks() in a loop — instead of 20 queries, Hibernate will do 2 queries (if batch size is 10).

🛠 Example scenario

You have:

  • Entity Author
  • Each author has many lazy-loaded Book entities (@OneToMany(fetch = LAZY)).

❌ Without batch fetching

List<Author> authors = entityManager.createQuery(
    "SELECT a FROM Author a", Author.class
).getResultList();

for (Author author : authors) {
    List<Book> books = author.getBooks(); // triggers lazy load for each author
    System.out.println("Author: " + author.getName() + ", books count: " + books.size());
}

If authors.size() == 20, Hibernate will run:

  • 1 query for authors,
  • 20 separate queries for each author’s books,
  • total: 21 queries.

✅ With batch fetching

First, enable batching with @BatchSize on the collection:

@Entity
public class Author {
    @OneToMany(mappedBy = "author", fetch = FetchType.LAZY)
    @BatchSize(size = 5) // fetch 5 authors’ books in one query
    private List<Book> books;
}

Then, run the same code:

List<Author> authors = entityManager.createQuery(
    "SELECT a FROM Author a", Author.class
).getResultList();

for (Author author : authors) {
    List<Book> books = author.getBooks();
    System.out.println("Author: " + author.getName() + ", books count: " + books.size());
}

Now, Hibernate groups lazy loads into batches of 5:

  • 1 query for authors,
  • 4 queries for books (because 20 authors / batch size 5 = 4 batches),
  • total: 5 queries, not 21.

🔎 SQL logs comparison

Without batch:

-- Query 1: fetch authors
SELECT * FROM authors;

-- Then for each author (20 times):
SELECT * FROM books WHERE author_id = ?;
...

With batch size 5:

-- Query 1: fetch authors
SELECT * FROM authors;

-- Batch 1: books for authors 1-5
SELECT * FROM books WHERE author_id IN (?, ?, ?, ?, ?);

-- Batch 2: authors 6-10
SELECT * FROM books WHERE author_id IN (?, ?, ?, ?, ?);
...
(total 4 batches)

✅ Why it matters

  • Greatly reduces database round trips.
  • Keeps your associations lazy (good for flexibility) but avoids N+1 problem.
This entry was posted in Без рубрики. Bookmark the permalink.

Leave a Reply

Your email address will not be published.