TGViewer
Библиотека джависта | Java, Spring, Maven, Hibernate Библиотека джависта | Java, Spring, Maven, Hibernate @javaproglib · 22K subscribers
Post #7587 2.15K
🔧 Hibernate Batch Processing

@BatchSize и hibernate.jdbc.batch_size — две разные вещи, которые иногда путают. Разбираем обе.

🔹 Решение

▪️ JDBC batch insert/update

spring:
jpa:
properties:
hibernate:
jdbc:
batch_size: 50 # отправлять INSERT пачками по 50
order_inserts: true # группировать INSERT по типу сущности
order_updates: true # то же для UPDATE
cache:
use_second_level_cache: false


Без order_inserts: true батчинг часто не работает. Hibernate вперемешку отправляет INSERT для разных таблиц, JDBC driver не может их объединить.

@Transactional
public void saveAll(List<Order> orders) {
for (int i = 0; i < orders.size(); i++) {
entityManager.persist(orders.get(i));
if (i % 50 == 0) {
entityManager.flush();
entityManager.clear(); // освобождаем first-level cache
}
}
}


Без flush/clear каждые N записей first-level cache растёт до OOM при больших объёмах.

▪️ @BatchSize для загрузки коллекций

@Entity
public class Author {

@OneToMany(mappedBy = "author", fetch = FetchType.LAZY)
@BatchSize(size = 25)
private List<Book> books;
}


При загрузке 100 авторов и обращении к books — вместо 100 SELECT будет 4 (100/25). Hibernate собирает ID авторов в пачки и загружает WHERE author_id IN (?, ?, ..., ?).

Это не решение N+1, это смягчение его последствий. Правильное решение — JOIN FETCH или EntityGraph для конкретного запроса. @BatchSize — запасной вариант для случаев когда JOIN FETCH неприменим.

▪️ @BatchSize на уровне класса

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


Работает для загрузки по ID: entityManager.find(Book.class, id) будет батчиться. Полезно при большом количестве lazy-загружаемых ссылок типа @ManyToOne.

▪️ Проверка что батчинг реально работает

spring:
jpa:
show-sql: true
datasource:
url: jdbc:postgresql://...?reWriteBatchedInserts=true # для PostgreSQL


Для PostgreSQL нужен флаг reWriteBatchedInserts=true в URL — иначе JDBC драйвер отправляет запросы по одному даже при включённом батчинге Hibernate.

⚠️ Сущности с @GeneratedValue(strategy = IDENTITY) (auto-increment) не батчируются при INSERT — Hibernate вынужден получать ID после каждой вставки. Для батчинга используйте SEQUENCE стратегию с allocationSize равным batch_size.

══════ Навигация ══════
Вакансии • Задачи • Собесы

🐸 Библиотека джависта

#Enterprise
  • 🔥 10
  • 👍 5
  • ⚡ 1
More from @javaproglib
  1. Oct 14, 2026Post #7897
  2. Oct 14, 2026Почему разработчик планирует отдавать больше задач Claude Винсент Шмальбах описал план пер…
  3. Oct 14, 2026🛠 Контейнер запущен, а тест всё равно падает Порт уже открыт, но приложение ещё применяет…
  4. Oct 13, 2026🧠 Почему BigDecimal считает 2.0 и 2.00 разными Что выведут эти две строки? var a = new Bi…
  5. Oct 12, 2026👀 Как вы смотрите видео? Разбираете урок, слушаете интервью фоном или начинаете на телефо…
  6. Oct 10, 2026Post #7892
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →