Choosing a Hibernate Identifier Generation Strategy for New Entities
A decision guide for Hibernate ORM 6.x identifier generation. Use SEQUENCE with matching allocationSize for most relational tables, reserve IDENTITY for simple schemas, avoid TABLE for high concurrency, and validate with SQL logging and batch insert tests.
06 Apr 2026, 15:14 UTC

Pick a strategy before the first migration
The practical problem is not which identifier generation exists, it is which one lets you batch inserts, scale writes, and keep schema changes cheap. For Hibernate ORM 6.x with JPA 2.x+ on relational databases, the default safe choice for new tables is SEQUENCE with a matching allocationSize. Use IDENTITY only when you need the simplest schema and batch inserts are not required. Avoid TABLE for high-concurrency workloads and treat AUTO as a hidden decision.
Constraints that narrow the choice
- Hibernate ORM 6.x changed sequence optimizer defaults and AUTO mapping behavior. Confirm dialect DDL generation before upgrading.
- SEQUENCE requires database sequence support. allocationSize in the mapping must equal the database sequence INCREMENT. A mismatch causes duplicate key exceptions or skipped IDs under concurrent load.
- Changing generation strategy after data exists requires migration. Validate on a staging copy of production data.
Option comparison
| Strategy | Portability | Batch insert | Concurrency | Fit |
|---|---|---|---|---|
| SEQUENCE | High | Excellent with allocationSize | Low | General purpose |
| IDENTITY | High | Poor; disables JDBC batch insert | Low | Simple schemas |
| TABLE | High | Moderate | Moderate; table contention | Legacy |
| UUID | Very high | Good | None | Distributed keys |
Trade-offs in practice
SEQUENCE with allocationSize
Supports JDBC batch inserts because IDs are preallocated in memory. Requires a database sequence object and the sequence increment must match allocationSize. Hibernate 6 uses a pooled optimizer by default, so the DB is hit once per allocationSize IDs.
IDENTITY
Maps to auto-increment columns. The insert must be executed immediately to obtain the generated value, which disables addBatch for that entity. Simple schema, no extra objects, but poor throughput for bulk writes.
TABLE
Emulates a sequence via a table row. Portable but introduces row-level lock contention under concurrent inserts. Acceptable for legacy systems, not recommended for new high-write tables.
UUID
Avoids database round-trips and works well for distributed writes. Increases index size and can increase page fragmentation on clustered indexes. Choose a time-ordered variant if index locality matters.
Concrete mapping and validation
Example entity with SEQUENCE. Run this on a database that supports sequences, e.g., PostgreSQL or Oracle.
@Entity
@Table(name = "order_item")
public class OrderItem {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "order_item_seq")
@SequenceGenerator(
name = "order_item_seq",
sequenceName = "order_item_seq",
allocationSize = 50
)
private Long id;
// fields, getters, setters
}
Database side must match allocationSize:
-- PostgreSQL
CREATE SEQUENCE order_item_seq START WITH 1 INCREMENT BY 50;
Practical validation steps:
- Enable SQL logging and set
hibernate.jdbc.batch_sizeto a value > 0. Persist 100 entities in one transaction. With SEQUENCE and matching allocationSize the log shows a single sequence select followed by batched inserts. With IDENTITY the log shows individual inserts. - Compare Hibernate allocationSize against the database sequence INCREMENT. A mismatch indicates duplicate-key risk.
- Run concurrent inserts under TABLE and SEQUENCE strategies and compare lock waits or duplicate-key errors in the database log.
Limitations: SEQUENCE does not work on databases without sequence support. UUIDs enlarge primary keys and foreign keys. Changing strategy later requires a data migration and careful coordination of the sequence start value to avoid collisions.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.