@GeneratedValue Strategies
BeginnerAUTO delegates to the provider; IDENTITY uses DB auto-increment; SEQUENCE uses a DB sequence (most efficient for batch inserts); TABLE uses a dedicated ID table (avoid in production).
Overview
@GeneratedValue tells JPA how the primary key value should be generated. Four strategies: AUTO (provider-chosen, default), IDENTITY (DB auto-increment — prevents JDBC batch inserts), SEQUENCE (DB sequence with configurable allocation size — best for batch inserts), TABLE (sequence table — portable but slow and lock-prone — avoid in production). For MySQL with InnoDB, IDENTITY is common but SEQUENCE via a sequence emulation table is better for bulk operations. PostgreSQL natively supports sequences.
IDENTITY vs SEQUENCE
IDENTITY relies on DB auto-increment. Hibernate must execute the INSERT and immediately SELECT the generated key — this prevents batching. SEQUENCE pre-fetches ID blocks (allocationSize) from a DB sequence, enabling batched INSERTs.
// IDENTITY — simple, works with MySQL AUTO_INCREMENT
// ✗ Disables JDBC batch inserts (Hibernate needs each insert's ID immediately)
@Entity
public class Order {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
}
// SEQUENCE — pre-fetches ID blocks; enables batch inserts
// Works with PostgreSQL natively; MySQL needs a workaround sequence table
@Entity
@SequenceGenerator(
name = "order_seq",
sequenceName = "order_id_seq", // DB sequence name
allocationSize = 50 // pre-allocate 50 IDs per round-trip
)
public class Order {
@Id
@GeneratedValue(
strategy = GenerationType.SEQUENCE,
generator = "order_seq"
)
private Long id;
}
// With allocationSize=50:
// 1st ID fetch: SELECT nextval('order_id_seq') → 1
// Hibernate caches IDs 1-50 in memory — no DB call for the next 49 entities
// 51st entity: SELECT nextval → 51, caches 51-100, etc.MySQL-Specific: Emulating Sequences
MySQL does not have native sequences (until 8.x with sequences plugin). Emulate them with a sequence table or use the hi-lo algorithm with a table generator. For most applications, IDENTITY is acceptable; for bulk inserts, use dedicated ID generation service or UUID.
// Option 1 — TABLE strategy (portable but slow, lock-prone — avoid)
@Entity
@TableGenerator(
name = "order_tg",
table = "id_generator",
pkColumnName = "gen_name",
valueColumnName = "gen_val",
pkColumnValue = "order_id",
allocationSize = 50
)
public class Order {
@Id
@GeneratedValue(strategy = GenerationType.TABLE, generator = "order_tg")
private Long id;
}
// Option 2 — UUID (no sequence needed — good for distributed systems)
@Entity
public class Order {
@Id
@GeneratedValue(strategy = GenerationType.UUID) // JPA 3.1 / Hibernate 6
@UuidGenerator(style = UuidGenerator.Style.TIME) // Hibernate 6 — time-ordered
private UUID id;
}
// UUIDv7 (time-ordered) avoids random page splits in B-tree indexes
// Use org.hibernate.annotations.UuidGenerator for version controlBulk Insert Performance
IDENTITY strategy disables JDBC batching. To batch INSERT 10,000 rows efficiently, use SEQUENCE with allocationSize or manage IDs manually with a pre-assigned ID list.
// Batch insert — SEQUENCE strategy enables proper JDBC batching
# application.properties
spring.jpa.properties.hibernate.jdbc.batch_size=50
spring.jpa.properties.hibernate.order_inserts=true
spring.jpa.properties.hibernate.generate_statistics=true
@Service
@Transactional
public class BulkOrderService {
public void importOrders(List<CreateOrderDTO> dtos) {
int batchSize = 50;
for (int i = 0; i < dtos.size(); i++) {
Order order = new Order(dtos.get(i));
em.persist(order);
if (i % batchSize == 0 && i > 0) {
em.flush(); // flush batch to DB
em.clear(); // detach all entities — free memory
}
}
}
}
// With SEQUENCE + allocationSize=50 + jdbc.batch_size=50:
// Hibernate pre-fetches 50 IDs → builds 50-row INSERT batch → single DB round-trip
// With IDENTITY: 1 INSERT per row = 10,000 round-tripsKey Points to Remember
- 1IDENTITY uses DB auto-increment — simple but disables JDBC batch INSERT.
- 2SEQUENCE pre-fetches ID blocks (allocationSize) — enables batching; use for bulk inserts.
- 3TABLE strategy is portable but uses DB row locks — avoid in production.
- 4UUID (@GeneratedValue(strategy=UUID)) is useful for distributed systems with no sequence.
- 5UUIDv7 (time-ordered) avoids random B-tree index splits unlike random UUIDv4.
- 6For bulk inserts: flush + clear every N entities to avoid OutOfMemoryError from L1 cache growth.
Interview Questions
Sign in to ask AriaWhy does GenerationType.IDENTITY prevent JDBC batch inserts?
What is allocationSize in @SequenceGenerator and how does it improve performance?
What is the difference between IDENTITY and SEQUENCE generation strategies?
When would you use UUID as a primary key instead of a numeric sequence?
How do you efficiently insert 100,000 entities using JPA?
Ask Aria about @GeneratedValue Strategies
Your personal AI tutor — ask anything about this concept
Revision Status
Personal Notes
Sign in to save personal notes for this topic.
Discussion
Sign in to join the discussion.