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,
- Simple identifiers
- 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.