Hibernate
Spring Boot
Batch Inserts
Database Optimization
Java Persistence

How to enable batch inserts with Hibernate and Spring Boot

System Design practice on Codemia

Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.

Practice system design

Introduction

Hibernate can batch inserts, but it only does so when the configuration, identifier strategy, and persistence pattern all line up. In Spring Boot, enabling batching usually means setting Hibernate batch properties, inserting entities in groups, and avoiding features that force Hibernate to execute each insert immediately.

Turn on Hibernate batch settings

Start with the Hibernate properties in application.properties:

properties
spring.jpa.properties.hibernate.jdbc.batch_size=50
spring.jpa.properties.hibernate.order_inserts=true
spring.jpa.properties.hibernate.generate_statistics=true

These settings tell Hibernate to group inserts into batches, reorder inserts for better batching opportunities, and optionally expose statistics so you can verify that batching is actually happening.

If you use MySQL, the JDBC driver may also need:

properties
spring.datasource.url=jdbc:mysql://localhost:3306/app?rewriteBatchedStatements=true

Without driver support, the ORM configuration alone may not produce the expected database-side batching behavior.

Insert entities in loops and flush periodically

Hibernate keeps managed entities in the persistence context, so large insert jobs should flush and clear periodically:

java
1for (int i = 0; i < users.size(); i++) {
2    entityManager.persist(users.get(i));
3
4    if (i > 0 && i % 50 == 0) {
5        entityManager.flush();
6        entityManager.clear();
7    }
8}

This pattern does two things:

  • it gives Hibernate a chance to send the batched SQL
  • it prevents the persistence context from growing without bound

For large imports, periodic flush() and clear() are often as important as the batch-size property itself.

Identifier strategy can disable real batching

One of the biggest Hibernate batching traps is GenerationType.IDENTITY. With identity columns, Hibernate often has to execute each insert immediately to retrieve the generated key, which prevents efficient batching.

If you want stronger batching behavior, sequence-based or pooled identifier strategies are usually better:

java
1@Id
2@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "user_seq")
3@SequenceGenerator(name = "user_seq", sequenceName = "user_seq", allocationSize = 50)
4private Long id;

This is a major reason developers think batching is enabled when it is not actually happening.

saveAll() is not a guarantee by itself

Calling repository.saveAll(list) can be fine, but it does not automatically guarantee efficient batching. The underlying behavior still depends on:

  • Hibernate batch settings
  • transaction boundaries
  • identifier strategy
  • driver capabilities

So saveAll() is convenient, but the real work is done by the configuration and persistence context behavior underneath it.

Verify batching instead of assuming it

Do not assume batching works because the code looks batch-like. Check the logs, Hibernate statistics, or database monitoring.

If every insert still appears as a separate SQL round trip, look at:

  • identity-based IDs
  • driver flags
  • missing transaction boundaries
  • unexpected flushes triggered by other operations

Performance tuning is much easier once you confirm what the ORM is actually sending.

Keep transaction size realistic

Very large transactions can hold too much memory and too many locks. Very small transactions may prevent batching from helping enough. In practice, teams often batch in chunks such as 20, 50, or 100 entities and test with their actual database and schema.

There is no universal best batch size. Measure with real data.

Common Pitfalls

  • Setting hibernate.jdbc.batch_size but using GenerationType.IDENTITY, which often defeats batching.
  • Forgetting driver-specific requirements such as MySQL's rewriteBatchedStatements=true.
  • Inserting huge numbers of entities without periodic flush() and clear().
  • Assuming saveAll() alone guarantees efficient JDBC batching.
  • Never verifying with logs or statistics whether batching is really happening.

Summary

  • Enable Hibernate batching with the relevant Spring Boot Hibernate properties.
  • Flush and clear the persistence context periodically during large insert jobs.
  • Avoid identifier strategies that force Hibernate to execute inserts one by one.
  • Check JDBC driver behavior, especially on MySQL.
  • Verify batching with logs or statistics instead of assuming the configuration worked.

Related reading
Course
Beginner
27 lessons
10 hours
System Design Fundamentals

Build a strong foundation in designing scalable, reliable distributed systems.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

System Design practice on Codemia

Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.

Practice system design

All Rights Reserved.