Close

JPA - Primary Key Generation Strategies

[Last Updated: Aug 8, 2017]

Every JPA entity is required to have a field which maps to primary key of the database table. Such field must be annotated with @Id.

Simple vs Composite primary keys

A simple primary key consists of a single Java field which maps to a single table column.
A composite primary key consists of multiple Java fields which individually map to separate columns.

Supported types for a primary key

A simple primary key field or one of the composite primary key field should be one of the following types:

  • Any Java primitive type
  • any Any primitive wrapper type
  • java.lang.String
  • java.util.Date
  • java.sql.Date
  • java.math.BigDecimal
  • java.math.BigInteger

In this tutorial we are going to focus on generation strategies of simple primary key.

@GeneratedValue Annotation

 package javax.persistence;
 .........
 @Target({ElementType.METHOD, ElementType.FIELD})
 @Retention(RetentionPolicy.RUNTIME)
 public @interface GeneratedValue {
    GenerationType strategy() default GenerationType.AUTO;
    String generator() default "";
 }

This annotation defines the types of primary key generation strategies. If this annotation is not used then application is responsible to populate and manage @Id field values itself.

The use of the GeneratedValue annotation is only required to be supported for simple primary keys.

GenerationType enum defines four strategies: Generation Type . TABLE, Generation Type. SEQUENCE, Generation Type. IDENTITY and Generation Type. AUTO. Let's understand them with examples.

GenerationType.SEQUENCE

With this strategy, underlying persistence provider must use a database sequence to get the next unique primary key for the entities.

@Entity
public class MyEntity1 {
  @Id
  @GeneratedValue(strategy = GenerationType.SEQUENCE)
  private int myId;
  //getters/setters
    .............
}

We have created the following Util class to reuse the code for other examples.

public class Util {

  public static void runExampleFor(String persistenceUnit, Class<?> entity) throws Exception{
      EntityManagerFactory emf = Persistence.createEntityManagerFactory(persistenceUnit);
      EntityManager em = emf.createEntityManager();

      nativeQuery(em, "SHOW TABLES");
      nativeQuery(em, "SELECT * FROM INFORMATION_SCHEMA.SEQUENCES");
      nativeQuery(em, "SHOW COLUMNS from "+ entity.getSimpleName());

      Object entity1 = entity.newInstance();
      Object entity2 = entity.newInstance();
      em.getTransaction().begin();
      em.persist(entity1);
      em.persist(entity2);
     em.getTransaction().commit();

      nativeQuery(em, "SELECT * FROM "+entity.getSimpleName());

      em.close();
      emf.close();
  }

  private static void nativeQuery(EntityManager entityManager, String s) {
      System.out.println("--------\n" + s);
      Query query = entityManager.createNativeQuery(s);
      List list = query.getResultList();
      for (Object o : list) {
          if (o instanceof Object[]) {
              System.out.println(Arrays.toString((Object[]) o));
          } else {
              System.out.println(o);
          }
      }
  }
}

Also, in the persistence.xml, we have created four persistence-unit, so that we can try four GenerationType independently. We are using Hibernate as persistence provider.

Let's create main class to try out Entity1 key generation.

public class GenerationTypeSequenceExample {

  public static void main(String[] args) throws Exception {
      Util.runExampleFor("test1", MyEntity1.class);
  }
}

Output

--------
SHOW TABLES
[MYENTITY1, PUBLIC]
--------
SELECT * FROM INFORMATION_SCHEMA.SEQUENCES
[TEST, PUBLIC, HIBERNATE_SEQUENCE, 0, 1, false, , 32, 1, 9223372036854775807, false, 4]
--------
SHOW COLUMNS from MyEntity1
[MYID, INTEGER(10), NO, PRI, NULL]
--------
SELECT * FROM MyEntity1
1
2

Above output shows one table MYENTITY1 and one sequence HIBERNATE_SEQUENCE are created.

GenerationType.TABLE

With this strategy, underlying persistence provider must use a database table to generate/keep the next unique primary key for the entities.

@Entity
public class MyEntity2 {
  @Id
  @GeneratedValue(strategy = GenerationType.TABLE)
  private int myId;
  //getters/setters
    .............
}
public class GenerationTypeTableExample {

  public static void main(String[] args) throws Exception {
      Util.runExampleFor("test2", MyEntity2.class);
  }
}

Output

--------
SHOW TABLES
[HIBERNATE_SEQUENCES, PUBLIC]
[MYENTITY2, PUBLIC]
--------
SELECT * FROM INFORMATION_SCHEMA.SEQUENCES
--------
SHOW COLUMNS from MyEntity2
[MYID, INTEGER(10), NO, PRI, NULL]
--------
SELECT * FROM MyEntity2
1
2

This time no sequence is generated, instead an additional table named 'HIBERNATE_SEQUENCES' is created to maintain primary key sequence.

GenerationType.IDENTITY

This GenerationType indicates that the persistence provider must assign primary keys for the entity using a database identity column. IDENTITY column is typically used in SQL Server. This special type column is populated internally by the table itself without using a separate sequence. If underlying database doesn't support IDENTITY column or some similar variant then the persistence provider can choose an alternative appropriate strategy. In this examples we are using H2 database which doesn't support IDENTITY column.

@Entity
public class MyEntity3 {

  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  private int myId;

  public int getMyId() {
      return myId;
  }

  public void setMyId(int myId) {
      this.myId = myId;
  }
}
public class GenerationTypeIdentityExample {

  public static void main(String[] args) throws Exception {
      Util.runExampleFor("test3", MyEntity3.class);
  }
}

Output

--------
SHOW TABLES
[MYENTITY3, PUBLIC]
--------
SELECT * FROM INFORMATION_SCHEMA.SEQUENCES
[TEST, PUBLIC, SYSTEM_SEQUENCE_CD0D1EC6_3C7C_48DF_A94C_04CE80722787, 0, 1, true, , 32, 1, 9223372036854775807, false, 5]
--------
SHOW COLUMNS from MyEntity3
[MYID, INTEGER(10), NO, PRI, (NEXT VALUE FOR PUBLIC.SYSTEM_SEQUENCE_CD0D1EC6_3C7C_48DF_A94C_04CE80722787)]
--------
SELECT * FROM MyEntity3
1
2

Above output shows that a sequence is used for primary keys.

GenerationType.AUTO

This GenerationType indicates that the persistence provider should automatically pick an appropriate strategy for the particular database. This is the default GenerationType, i.e. if we just use @GeneratedValue annotation then this value of GenerationType will be used.

@Entity
public class MyEntity4 {
  @Id
  @GeneratedValue(strategy = GenerationType.AUTO)
  private int myId;

  public int getMyId() {
      return myId;
  }

  public void setMyId(int myId) {
      this.myId = myId;
  }
}
public class GenerationTypeAutoExample {

  public static void main(String[] args) throws Exception {
          Util.runExampleFor("test4", MyEntity4.class);
  }
}

Output

--------
SHOW TABLES
[MYENTITY4, PUBLIC]
--------
SELECT * FROM INFORMATION_SCHEMA.SEQUENCES
[TEST, PUBLIC, HIBERNATE_SEQUENCE, 0, 1, false, , 32, 1, 9223372036854775807, false, 4]
--------
SHOW COLUMNS from MyEntity4
[MYID, INTEGER(10), NO, PRI, NULL]
--------
SELECT * FROM MyEntity4
1
2

Above output shows that a sequence is used for primary keys.

When @GeneratedValue not used

If we don't use @GeneratedValue annotation at all, then we have to populate the unique primary keys ourselves. In this example, we are simply assigning it to the value returned from System.nanoTime()

@Entity
public class MyEntity5 {
  @Id
  private long myId = System.nanoTime();

  public long getMyId() {
      return myId;
  }

  public void setMyId(long myId) {
      this.myId = myId;
  }
}
public class NoGeneratedValueExample {

  public static void main(String[] args) throws Exception {
      Util.runExampleFor("test5", MyEntity5.class);
  }
}

Output

--------
SHOW TABLES
[MYENTITY5, PUBLIC]
--------
SELECT * FROM INFORMATION_SCHEMA.SEQUENCES
--------
SHOW COLUMNS from MyEntity5
[MYID, BIGINT(19), NO, PRI, NULL]
--------
SELECT * FROM MyEntity5
614063143407256
614063143411057

Above output shows that a no sequence or extra table were generated.

Example Project

Dependencies and Technologies Used:

  • h2 1.4.193: H2 Database Engine.
  • hibernate-core 5.2.8.Final: The core O/RM functionality as provided by Hibernate.
    Implements javax.persistence:javax.persistence-api version 2.1
  • JDK 1.8
  • Maven 3.3.9

Jpa Primary Key Generation Select All Download
  • jpa-key-generation-strategies
    • src
      • main
        • java
          • com
            • logicbig
              • example
                • MyEntity1.java
          • resources
            • META-INF

    See Also