How to change JPA Id Generator

Using hibernate sequence generator to change the behavior of the id generation.

, updated

When working with JPA and Hibernate, you’ll often need to control how primary key IDs are generated. By default, Hibernate uses an auto-increment strategy that varies across databases. The @GeneratedValue annotation together with @SequenceGenerator gives you fine-grained control over ID generation.

The Problem

If you just use @GeneratedValue(strategy = GenerationType.AUTO), Hibernate will pick a strategy depending on the database dialect. This can lead to:

  • A separate sequence table (hibernate_sequence) being created unexpectedly
  • ID values that don’t match what you expect
  • Portability issues between dev (H2) and production (PostgreSQL/Oracle)

Using Sequence Generator

A @SequenceGenerator lets you define a database sequence with a specific name, allocation size, and initial value:

@Entity
public class Product {

    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "product_seq")
    @SequenceGenerator(
        name = "product_seq",
        sequenceName = "product_id_seq",
        allocationSize = 1,
        initialValue = 1
    )
    private Long id;

    // ...
}
  • name — the name Hibernate uses to reference this generator (in @GeneratedValue)
  • sequenceName — the actual database sequence object name
  • allocationSize — how many IDs Hibernate pre-fetches from the sequence (default is 50; set to 1 for sequential IDs)
  • initialValue — the starting value of the sequence

Using Identity Generator

For databases that support auto-increment columns (MySQL, PostgreSQL, SQL Server), use GenerationType.IDENTITY:

@Entity
public class Product {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    // ...
}

This maps to the database’s native auto-increment column. It’s simple but doesn’t support batch inserts since Hibernate must query the database after each insert to get the generated ID.

Using a Table Generator

If you need portability across databases that don’t support sequences, use @TableGenerator:

@Entity
public class Product {

    @Id
    @GeneratedValue(strategy = GenerationType.TABLE, generator = "product_gen")
    @TableGenerator(
        name = "product_gen",
        table = "id_generator",
        pkColumnName = "gen_name",
        valueColumnName = "gen_value",
        pkColumnValue = "product_gen",
        allocationSize = 10
    )
    private Long id;

    // ...
}

This creates a table that stores the next ID value. It’s the most portable approach but slower than native sequences.

Switching Strategies Dynamically

If you need to use different strategies in dev vs. production (e.g., H2 identity vs. PostgreSQL sequence), configure it in your application.properties:

# For H2 in dev
spring.jpa.properties.hibernate.id.db_strategy=native

# Or specify the dialect
spring.jpa.database-platform=org.hibernate.dialect.PostgreSQLDialect

Overriding Generated Values for Merges

Sometimes you need to insert an entity with a specific ID (e.g., during data migration). You can bypass @GeneratedValue during a merge:

// Persist with a specific ID by using merge instead of persist
Product product = new Product();
product.setId(42L);  // manually set ID
product.setName("Migrated Product");

entityManager.merge(product);

Note: persist() will throw an exception if the ID is already set, while merge() will handle it.

External Resources