In this tutorial, you will learn primary key generation strategies in JPA/Hibernate. Identifiers represent the primary key of an entity and they uniquely identify each entity. I am hoping, you have a good understanding of Entity Mapping.

Hibernate and JPA assumes that the field annotated with @Id is

  • UNIQUE – The value in the DB table is unique.
  • NOT NULL – The column can not be null.
  • IMMUTABLE – Once the values inserted, can never be changed.
@Id
@Column(name = "id", nullable = false, updatable = false)
@GeneratedValue
private Integer id;

The above code is as good as writing below because of the above-discussed assumptions.

@Id
@GeneratedValue
private Integer id;

Mutable fields are annotated with @NaturalId

There are 2 ways to use identities in JPA,

  1. Simple identifiers
  2. Composite identifiers

Overview of Simple Identifiers

Simple identifiers are mapped to a single basic attribute (single DB column) and annotated with @javax.persistence.Id. Only the following types are supported for the Primary key field.

  • Any Java primitive type e.g. int, long, double and etc.
  • Any primitive wrapper class, e.g. Integer, Long, Double and etc
  • java.lang.String
  • java.util.Date (TemporalType#DATE)
  • java.sql.Date
  • java.math.BigDecimal
  • java.math.BigInteger

Identifiers values can be assigned before save/persist. This is called assigned identifiers.

@Id
private Integer id;

In most of the practical use cases, the @Id field value is generated by the JPA providers (Hibernate) using javax.persistence.GeneratedValue annotation as shown below. These ids are known as Generated Identifiers.

@Id
@GeneratedValue
private Integer id;

Primary key value generation strategy JPA ( Hibernate )

Generated identifiers are indicated by @javax.persistence.GeneratedValue as discussed above. There are basically 4 strategies to generate values of id fields.

These are AUTO, IDENTITY, SEQUENCE and TABLE.

package javax.persistence;

/** 
 * Defines the types of primary key generation strategies. 
 *
 */
public enum GenerationType { 
    /**
     * Indicates that the persistence provider must assign 
     * primary keys for the entity using an underlying 
     * database table to ensure uniqueness.
     */
    TABLE, 

    /**
     * Indicates that the persistence provider must assign 
     * primary keys for the entity using a database sequence.
     */
    SEQUENCE, 

    /**
     * Indicates that the persistence provider must assign 
     * primary keys for the entity using a database identity column.
     */
    IDENTITY, 

    /**
     * Indicates that the persistence provider should pick an 
     * appropriate strategy for the particular database. The 
     * <code>AUTO</code> generation strategy may expect a database 
     * resource to exist, or it may attempt to create one. A vendor 
     * may provide documentation on how to create such resources 
     * in the event that it does not support schema generation 
     * or cannot create the schema resource at runtime.
     */
    AUTO
}

1. GenerationType.AUTO strategy

GenerationType.AUTO is the default strategy. This lets the JPA implementor (Hibernate) to choose the best strategy based on the database dialect. For most of the common databases, it picks GenerationType.SEQUENCE.

@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;

When you are not sure which id generation strategy to use, just use @GeneratedValue, this will make use of @GeneratedValue(strategy = GenerationType.AUTO).

2. GenerationType.IDENTITY strategy

GenerationType.IDENTITY lets the database to generate this value, mostly by an auto-increment logic. This strategy may be best for the database but has a performance issue from the application perspective.

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

Most common performance issue using this strategy is Batch processing. Insert of doing a batch insert, hibernate will go on inserting one by one, hence impacting the number of queries that get executed.

3. GenerationType.SEQUENCE strategy

GenerationType.SEQUENCE is the advised way to generate primary key values and hibernate uses a database sequence to generate unique values.

@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE)
private Integer id;

The GenerationType.SEQUENCE requires additional select statements to get the next value from a database sequence. This has no known performance issues, suitable for large data processing with some hibernate related optimization.

NOTE: Additionally, you can pass a @SequenceGenerator reference in the @GeneratedValue configuration. The @SequenceGenerator annotation lets you define the name of the database-sequenceName, the generator name, the schema of the database sequence, and the allocation size of the sequence.

@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "inst_seq")
@SequenceGenerator(name = "inst_seq")
private Integer id;

Below is the source code of the @SequenceGenerator annotation.

package javax.persistence;
//All imports here
import java.lang.annotation.Repeatable;

/**
 * Defines a primary key generator that may be referenced by name when
 * a generator element is specified for the {@link GeneratedValue}
 * annotation. A sequence generator may be specified on the entity
 * class or on the primary key field or property. The scope of the
 * generator name is global to the persistence unit (across all
 * generator types).
 *
 * <pre>
 *   Example:
 *
 *   @SequenceGenerator(name="EMP_SEQ", allocationSize=25)
 * </pre>
 *
 * @since Java Persistence 1.0
 */
@Repeatable(SequenceGenerators.class)
@Target({TYPE, METHOD, FIELD}) 
@Retention(RUNTIME)
public @interface SequenceGenerator {

    /** 
     * (Required) A unique generator name that can be referenced 
     * by one or more classes to be the generator for primary key 
     * values.
     */
    String name();

    /**
     * (Optional) The name of the database sequence object from 
     * which to obtain primary key values.
     * <p> Defaults to a provider-chosen value.
     */
    String sequenceName() default "";

    /** (Optional) The catalog of the sequence generator. 
     *
     * @since Java Persistence 2.0
     */
    String catalog() default "";

    /** (Optional) The schema of the sequence generator. 
     *
     * @since Java Persistence 2.0
     */
    String schema() default "";

    /** 
     * (Optional) The value from which the sequence object 
     * is to start generating.
     */
    int initialValue() default 1;

    /**
     * (Optional) The amount to increment by when allocating 
     * sequence numbers from the sequence.
     */
    int allocationSize() default 50;
}

4. GenerationType.TABLE strategy

GenerationType.TABLE is rarely used today. It simulates a sequence by storing and updating its current value in a database table, it uses pessimistic locks to put all transactions into sequential order. It has performance issues.

Prefer using GenerationType.SEQUENCE over this strategy.

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

In the summary, I advise you to use GenerationType.SEQUENCE, or just use GenerationType.AUTO. Don’t use the other 2. Keep the SequenceGenerator API doc handy. Just like SequenceGenerator, there is also TableGenerator which you can explore more if you would like to.

Please share your thoughts in the comments below, will appreciate your feedback.

By |Last Updated: August 24th, 2019|Categories: Hibernate, JPA|