May 06, 2017

#Part 4: Hibernate Interview Questions (Identifiers in Hibernate-JPA)

Generated Identifiers and Hibernate GeneratedValue Strategies
Hibernate provides a couple of generation strategies to generate a primary key in the database table. We can access the strategy with the help of @GeneratedValue annotation.

This annotation specifies how to generate values for the given column. This annotation will help in creating primary keys values according to the specified strategy. If we don’t use @GeneratedValue annotation, the application is responsible for managing the @Id field values itself. e.g:

@Id 
@GeneratedValue  
@Column(name="emp_id")   
private int empId;  

The @GeneratedValue annotation uses two parameters, strategy, and GenerationType. The GenerationType is an enum which defines the types of strategies. The strategies are: GenerationType.AUTO, GenerationType.IDENTITY, GenerationType.SEQUENCE and GenerationType.TABLE. If we don't specify a value explicitly, the generation type defaults to AUTO

GenerationType.AUTO
If we're using the default generation type, the persistence provider will determine values based on the type of the primary key attribute. This type can be numerical or UUID. For numeric values, the generation is based on a sequence or table generator, while UUID values will use the UUIDGenerator.

It is the default GenerationType, if no strategy is defined, it will consider AUTO by default. All the databases support this strategy.

Hibernate 5 has introduced UUIDGenerator feature. To use this, all we need to do is declare an id of type UUID with @GeneratedValue annotation. Hibernate will generate an id of the form '9dd5f111-9788-9d11-81bb-11eed9eff999'. e.g:

@Id 
@GeneratedValue  
@Column(name="emp_id")   
private UUID empId;

GenerationType.IDENTITY 
It indicates that the persistence provider must assign primary keys for the entities using a database identity column, which means they will be auto-incremented. It is very similar to AUTO generationType. This strategy is not available in all the databases. If the particular database doesn’t support IDENTITY generationtype, the persistence provider will itself choose an alternative strategy. FYI, IDENTITY generation disables batch updates.

GenerationType.SEQUENCE 
This strategy consists of two parts, defining a sequence name and using the sequence name in the classes. To use a sequence-based id, Hibernate provides the SequenceStyleGenerator class. This generator uses sequences if they're supported by our database, and switches to table generation if they aren't.  A SEQUENCE GenerationType is global to the application; it can be accessed by one or more entities in the application.

To customize the sequence name, we can use the @GenericGenerator annotation with SequenceStyleGenerator strategy.

@Id
@GeneratedValue(generator = "sequence-generator")
@GenericGenerator(
name = "sequence-generator",
strategy = "org.hibernate.id.enhanced.SequenceStyleGenerator",
parameters = {
@Parameter(name = "sequence_name", value = "employee_sequence"),
@Parameter(name = "initial_value", value = "9"),
}
)
private long empId;

In the above example, we've also set an initial value for the sequence, which means the primary key generation will start at 9.

FYI, the generated values are unique per sequence. If you don't specify a sequence name, Hibernate will re-use the same hibernate_sequence for different types.

GenerationType.TABLE 
It indicates that the persistence provider must assign primary keys for the entities using a database table. It uses a database table to store the latest primary key value. This strategy is available in all the databases.

@Id
@GeneratedValue(strategy = GenerationType.TABLE, 
generator = "table-generator")
@TableGenerator(name = "table-generator", 
table = "employees", 
pkColumnName = "emp_id", 
valueColumnName = "seq_value")
private long empId;

In the above example, we can see that other attributes such as the pkColumnName and valueColumnName can also be customized. The disadvantage of this method is that it doesn't scale well and can negatively affect performance.

Custom Generator
We can also define our custom generator by implementing the IdentifierGenerator interface. e.g:



In the above example IdentifierGenerator overrides the generate() method from the IdentifierGenerator interface. We are doing something to get the highest number from the existing primary keys of the form prefix-X and incrementing it by 1 to obtain the newly generated id value.

We will discuss about the Composite and Derived Identifiers in the next blogpost.

-K Himaanshu Shuklaa..

No comments:

Post a Comment