Gymterview
senior

Batch-операции в Hibernate

Batch-операции позволяют выполнять массовые INSERT/UPDATE/DELETE эффективно, группируя SQL-запросы в пакеты вместо отправки по одному.

Настройка batch insert/update

Пример
# application.properties
spring.jpa.properties.hibernate.jdbc.batch_size=50
spring.jpa.properties.hibernate.order_inserts=true
spring.jpa.properties.hibernate.order_updates=true
spring.jpa.properties.hibernate.jdbc.batch_versioned_data=true

Batch INSERT

Пример
@Transactional
public void batchInsert(List<User> users) {
    for (int i = 0; i < users.size(); i++) {
        entityManager.persist(users.get(i));

        if (i % 50 == 0) { // batch_size = 50
            entityManager.flush();  // отправить SQL в БД
            entityManager.clear();  // очистить L1 Cache (освободить память)
        }
    }
}

IDENTITY vs SEQUENCE для batch

Пример
// IDENTITY — batch insert НЕВОЗМОЖЕН!
// Hibernate выполняет INSERT сразу для получения ID
@GeneratedValue(strategy = GenerationType.IDENTITY) // не подходит для batch

// SEQUENCE — batch insert РАБОТАЕТ
// Hibernate заранее получает блок ID из sequence
@GeneratedValue(strategy = GenerationType.SEQUENCE,
                generator = "user_seq")
@SequenceGenerator(name = "user_seq", allocationSize = 50) // подходит для batch

Bulk UPDATE/DELETE (JPQL — обходит Persistence Context)

Пример
@Modifying
@Query("UPDATE User u SET u.status = :status WHERE u.lastLogin < :date")
int deactivateInactiveUsers(@Param("status") UserStatus status,
                            @Param("date") LocalDateTime date);
// Один SQL UPDATE, без загрузки сущностей
// ВАЖНО: @Modifying(clearAutomatically = true) — очистить L1 Cache после

Важное

  • batch_size — количество SQL-операций, группируемых в один batch
  • order_inserts/order_updates — обязательно для эффективного batch (группировка по таблицам)
  • flush() + clear() каждые N записей — предотвращение OutOfMemoryError при больших batch
  • SEQUENCE стратегия генерации ID — обязательна для batch INSERT (IDENTITY не поддерживает batch)

Частые ошибки

  • IDENTITY + batch — Hibernate выполняет INSERT по одному; batch не работает
  • Не вызывать clear() — L1 Cache растёт с каждой persist(), 1M сущностей → OOM
  • Bulk UPDATE без clearAutomatically — L1 Cache содержит устаревшие данные, следующий find() вернёт старое значение
  • Не включить order_inserts — без сортировки Hibernate перемешивает INSERT разных таблиц, batch не формируется

Как используется в 2026

  • Для массовых операций (импорт данных, миграции) — JDBC batch напрямую (через JdbcTemplate) или jOOQ
  • Hibernate batch — для умеренных объёмов (тысячи, не миллионы)
  • Spring Batch — для ETL-задач с миллионами записей
  • @Modifying JPQL — для bulk UPDATE/DELETE; самый простой способ массового обновления

На собеседовании: ключевые моменты: batch_size + order_inserts + SEQUENCE (не IDENTITY!). Объясните, почему IDENTITY блокирует batch insert (Hibernate должен выполнить INSERT сразу для получения ID). Упомяните flush/clear паттерн для предотвращения OOM. Для миллионов записей — JDBC напрямую или Spring Batch.