Enterprise Java

Identifiers In Hibernate

Introduction:

Identifiers in Hibernate model the primary key attribute of an entity. It helps us to uniquely identify a JPA entity. Every entity must define an identifier. Also, it can be either simple or composite.

We can define a Hibernate identifier in several ways. In this tutorial, we’ll learn how to do so.

Simple (Single-Valued) Identifier:

If we have a single attribute which can uniquely identify our entity, we can simply annotate that attribute with @Id annotation:

Java

@Entity
public class Employee {
 
    @Id
    private Integer empId;
     
    ...
}

Please remember that the attribute being annotated with @Id should be one of the following types:

  • any Java primitive type or any primitive wrapper type
  • String
  • any of the Java Date types, Or
  • a BigDecimal or a BigInteger

Simple-Generated Identifiers:

What if we want our id values to be auto-generated? For it, we can go a step further and use @GeneratedValue annotation on our identifier field:

Java

@Entity
public class Employee {
    
    @Id
    @GeneratedValue
    public Integer empId;
    ...
}

When using @GeneratedValue, Hibernate generates the value for our id column while persisting an entity. It’ s important for us to remember that we can only auto-generate either an integral type (int, short or long) or a UUID.

Also, we have four different key generation strategies available to auto-generate our identifier’s value:

1. AUTO Generation Strategy:

Hibernate uses AUTO key generation strategy as its default. The behavior of AUTO strategy slightly varies from one JPA persistence provider to another. In the case of Hibernate, if the identifier attribute is of type UUID it uses the UUIDGenerator or else defaults to the sequence generation strategy.

UUID generation is supported only in Hibernate 5 and higher versions and is of 36 characters in length:

Java

@Entity
public class Employee {
 
    @Id
    @GeneratedValue
    private UUID empId;
 
    ...
}

The generated UUID is of the form ‘4ee5a777-7981-4e01-06ab-19aabb2eaa122’.

2. IDENTITY Generation Strategy:

For IDENTITY generation strategy, Hibernate uses IdentityGenerator to generate the identifier values. The values are generated by the identity column of the database and are auto-incremented:

Java

@Entity
public class Employee {
 
    @Id
    @GeneratedValue (strategy = GenerationType.IDENTITY)
    private Integer empId;
 
    ...
}

A major drawback of using this strategy is that it doesn’t support batch JDBC insertions.

3. SEQUENCE Generation Strategy:

Here, as the name suggests, database sequences are used to generate the values for our identifier. Hibernate uses SequenceStyleGenerator class internally to achieve it. If our database doesn’t support sequences, it automatically switches to the TABLE key generation strategy.

The SEQUENCE generator generates unique values per sequence. We can either specify the database sequence we wish to use:

Java

@Entity
public class Employee {
    
    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE,
      generator = "emp_generator")
    @SequenceGenerator(name = "emp_generator",
      sequenceName = "emp_seq", allocationSize = 100)
    public Integer empId;
    ...
}

Or else Hibernate will use the implicitly-named sequence hibernate_sequence:

Java

@Entity
public class Employee {
    
    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE)
    public Integer empId;
    ...
}

to generate the values for our identifier field.

4. TABLE Generation Strategy:

The Hibernate TableGenerator uses a table capable of holding multiple segments of an identifier generation values. Unless specified, Hibernate uses the hibernate_sequences table by default:

Java

@Entity
public class Employee {
    
    @Id
    @GeneratedValue(strategy = GenerationType.TABLE)
    public Integer empId;
    ...
}

We can use @TableGenerator to specify the database table to be used for generating the values:

Java

@Entity
    public class Employee {
 
        @Id
        @GeneratedValue(strategy = GenerationType.TABLE, generator = "emp_generator") 
        @TableGenerator(name = "emp_generator",
          table = "emp_generator_tbl",
          schema = "employees")
        public Integer empId;
        
        ...
 
 }

The TABLE strategy is not very scalable and has a poor performance, so hardly used in real-world implementations. We should always prefer using SEQUENCE generation strategy for all databases that support sequences, which most often all modern databases do.

Composite Identifiers:

Hibernate also allows us to define a composite identifier. To define a composite identifier, we create a primary key class holding the persistent attributes that form our composite key. As per the JPA specifications, our primary key class must be:

  1. Annotated with @EmbeddedId or @IdClass annotations
  2. public and have a public no-args constructor
  3. Serializable
  4. Implementing equals() and hashCode() methods

The attributes making up the composition could be basic, composite or ManyToOne. However, collections and OneToOne attributes aren’t considered appropriate.

1. Using @EmbeddedId:

One way of defining and using a composite key is using @EmbeddedId annotation.

So, let’s start by defining our primary key class and annotating it with @Embeddable:

Java

@Embeddable
public class EmployeePurchasesPK implements Serializable {
 
    private long empId;
    private long productId;
 
    //equals() and hashCode() methods
    ...
}

Now, we can easily reference this class from our entity using @EmbeddedId annotation:

Java

@Entity
public class EmployeePurchases {
 
    @EmbeddedId
    private EmployeePurchasesPK primaryAttributes;
 
    ...
}

To use our entity class to set or retrieve the primary key attributes, we’ll have something like:

Java

EmployeePurchasesPK primaryAttributes = new EmployeePurchasesPK();
primaryAttributes.setEmpId(1001);
primaryAttributes.setProductId(7822);
 
EmployeePurchases empPurchases = new EmployeePurchases();
empPurchases.setPrimaryAttributes(primaryAttributes);
...

Clearly, our EmployeePurchases entity has a composite key composed of empId and productId.

2. Using @IdClass:

When using @IdClass to create a composite key, we can use @Id annotation to define all our composition attributes in our main class. The code in our primary key class remains as-is but it only acts as a “shadow”:

Java

@Entity
@IdClass(EmployeePurchasesPK.class)
public class EmployeePurchases {
 
    @Id
    private long empId;
 
    @Id
    private long productId;
 
    ...
 
}

With this approach, we can directly set the key values using getters/setters of our main entity class:

Java

EmployeePurchases empPurchases = new EmployeePurchases(); 
empPurchases.setEmpId(1011);
empPurchases.setProductId(9331);
...

However, this method doesn’t provide us with a clear separation between the identifier and our entity object.

Derived Identifiers:

In Hibernate, we can choose to copy the entity’s identifier value from one of its associations using @MapsId annotation:

Java

public class EmployeeHistory {
 
    @Id
    private long id;
 
    @OneToOne
    @MapsId
    private Employee employee;
 
    ...
 
}

Here, our EmployeeHistory instance will have the exact same id as that of the corresponding Employee instance.

Conclusion:

In this tutorial, we looked at multiple ways to define an identifier in Hibernate. We also covered different key auto-generation strategies.

Be the First to comment.

Published on Java Code Geeks with permission by Shubhra Srivastava, partner at our JCG program. See the original article here: Identifiers In Hibernate

Opinions expressed by Java Code Geeks contributors are their own.

Shubhra Srivastava

Shubhra is a software professional and founder of ProgrammerGirl. She has a great experience with Java/J2EE technologies and frameworks. She loves the amalgam of programming and coffee :)
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Inline Feedbacks
View all comments
Back to top button